chore: clean up unused variables and improve error handling across codebase

This commit focuses on removing unused variables, adding placeholder error handling, and generally tidying up various files across the Dokploy application. Changes include:

- Removing unused imports and variables
- Adding placeholder error handling in catch blocks
- Cleaning up commented-out code
- Removing deprecated utility files
- Improving type safety and code consistency
This commit is contained in:
Mauricio Siu
2025-02-22 20:35:21 -06:00
parent 1a415b96c9
commit 8ab6d6b282
132 changed files with 375 additions and 471 deletions

View File

@@ -130,7 +130,7 @@ const createStringToJSONSchema = (schema: z.ZodTypeAny) => {
} }
try { try {
return JSON.parse(str); return JSON.parse(str);
} catch (e) { } catch (_e) {
ctx.addIssue({ code: "custom", message: "Invalid JSON format" }); ctx.addIssue({ code: "custom", message: "Invalid JSON format" });
return z.NEVER; return z.NEVER;
} }

View File

@@ -77,7 +77,7 @@ export const UpdateVolume = ({
serviceType, serviceType,
}: Props) => { }: Props) => {
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const utils = api.useUtils(); const _utils = api.useUtils();
const { data } = api.mounts.one.useQuery( const { data } = api.mounts.one.useQuery(
{ {
mountId, mountId,

View File

@@ -84,7 +84,6 @@ export const SaveBitbucketProvider = ({ applicationId }: Props) => {
data: repositories, data: repositories,
isLoading: isLoadingRepositories, isLoading: isLoadingRepositories,
error, error,
isError,
} = api.bitbucket.getBitbucketRepositories.useQuery( } = api.bitbucket.getBitbucketRepositories.useQuery(
{ {
bitbucketId, bitbucketId,

View File

@@ -27,8 +27,7 @@ export const ShowGeneralApplication = ({ applicationId }: Props) => {
const { mutateAsync: stop, isLoading: isStopping } = const { mutateAsync: stop, isLoading: isStopping } =
api.application.stop.useMutation(); api.application.stop.useMutation();
const { mutateAsync: deploy, isLoading: isDeploying } = const { mutateAsync: deploy } = api.application.deploy.useMutation();
api.application.deploy.useMutation();
const { mutateAsync: reload, isLoading: isReloading } = const { mutateAsync: reload, isLoading: isReloading } =
api.application.reload.useMutation(); api.application.reload.useMutation();

View File

@@ -279,7 +279,7 @@ export const ShowPreviewSettings = ({ applicationId }: Props) => {
<FormField <FormField
control={form.control} control={form.control}
name="env" name="env"
render={({ field }) => ( render={() => (
<FormItem> <FormItem>
<FormControl> <FormControl>
<Secrets <Secrets

View File

@@ -60,7 +60,7 @@ export const DeleteService = ({ id, type }: Props) => {
compose: () => compose: () =>
api.compose.one.useQuery({ composeId: id }, { enabled: !!id }), api.compose.one.useQuery({ composeId: id }, { enabled: !!id }),
}; };
const { data, refetch } = queryMap[type] const { data } = queryMap[type]
? queryMap[type]() ? queryMap[type]()
: api.mongo.one.useQuery({ mongoId: id }, { enabled: !!id }); : api.mongo.one.useQuery({ mongoId: id }, { enabled: !!id });

View File

@@ -118,7 +118,7 @@ export const ShowDomainsCompose = ({ composeId }: Props) => {
await deleteDomain({ await deleteDomain({
domainId: item.domainId, domainId: item.domainId,
}) })
.then((data) => { .then((_data) => {
refetch(); refetch();
toast.success("Domain deleted successfully"); toast.success("Domain deleted successfully");
}) })

View File

@@ -35,8 +35,7 @@ export const ComposeFileEditor = ({ composeId }: Props) => {
{ enabled: !!composeId }, { enabled: !!composeId },
); );
const { mutateAsync, isLoading, error, isError } = const { mutateAsync, isLoading } = api.compose.update.useMutation();
api.compose.update.useMutation();
const form = useForm<AddComposeFile>({ const form = useForm<AddComposeFile>({
defaultValues: { defaultValues: {
@@ -76,7 +75,7 @@ export const ComposeFileEditor = ({ composeId }: Props) => {
composeId, composeId,
}); });
}) })
.catch((e) => { .catch((_e) => {
toast.error("Error updating the Compose config"); toast.error("Error updating the Compose config");
}); });
}; };

View File

@@ -84,7 +84,6 @@ export const SaveBitbucketProviderCompose = ({ composeId }: Props) => {
data: repositories, data: repositories,
isLoading: isLoadingRepositories, isLoading: isLoadingRepositories,
error, error,
isError,
} = api.bitbucket.getBitbucketRepositories.useQuery( } = api.bitbucket.getBitbucketRepositories.useQuery(
{ {
bitbucketId, bitbucketId,

View File

@@ -70,7 +70,7 @@ export const IsolatedDeployment = ({ composeId }: Props) => {
composeId, composeId,
isolatedDeployment: formData?.isolatedDeployment || false, isolatedDeployment: formData?.isolatedDeployment || false,
}) })
.then(async (data) => { .then(async (_data) => {
randomizeCompose(); randomizeCompose();
refetch(); refetch();
toast.success("Compose updated"); toast.success("Compose updated");

View File

@@ -39,7 +39,7 @@ type Schema = z.infer<typeof schema>;
export const RandomizeCompose = ({ composeId }: Props) => { export const RandomizeCompose = ({ composeId }: Props) => {
const utils = api.useUtils(); const utils = api.useUtils();
const [compose, setCompose] = useState<string>(""); const [compose, setCompose] = useState<string>("");
const [isOpen, setIsOpen] = useState(false); const [_isOpen, _setIsOpen] = useState(false);
const { mutateAsync, error, isError } = const { mutateAsync, error, isError } =
api.compose.randomizeCompose.useMutation(); api.compose.randomizeCompose.useMutation();
@@ -76,7 +76,7 @@ export const RandomizeCompose = ({ composeId }: Props) => {
suffix: formData?.suffix || "", suffix: formData?.suffix || "",
randomize: formData?.randomize || false, randomize: formData?.randomize || false,
}) })
.then(async (data) => { .then(async (_data) => {
randomizeCompose(); randomizeCompose();
refetch(); refetch();
toast.success("Compose updated"); toast.success("Compose updated");

View File

@@ -40,7 +40,7 @@ export const ShowConvertedCompose = ({ composeId }: Props) => {
.then(() => { .then(() => {
refetch(); refetch();
}) })
.catch((err) => {}); .catch((_err) => {});
} }
}, [isOpen]); }, [isOpen]);

View File

@@ -29,14 +29,6 @@ interface Props {
data: ContainerMetric[]; data: ContainerMetric[];
} }
interface FormattedMetric {
timestamp: string;
read: number;
write: number;
readUnit: string;
writeUnit: string;
}
const chartConfig = { const chartConfig = {
read: { read: {
label: "Read", label: "Read",

View File

@@ -20,7 +20,7 @@ interface Props {
organizationId?: string; organizationId?: string;
children?: React.ReactNode; children?: React.ReactNode;
} }
export function AddOrganization({ organizationId, children }: Props) { export function AddOrganization({ organizationId }: Props) {
const utils = api.useUtils(); const utils = api.useUtils();
const { data: organization } = api.organization.one.useQuery( const { data: organization } = api.organization.one.useQuery(
{ {

View File

@@ -53,7 +53,7 @@ export const ShowCustomCommand = ({ id, type }: Props) => {
mongo: () => api.mongo.update.useMutation(), mongo: () => api.mongo.update.useMutation(),
}; };
const { mutateAsync, isLoading } = mutationMap[type] const { mutateAsync } = mutationMap[type]
? mutationMap[type]() ? mutationMap[type]()
: api.mongo.update.useMutation(); : api.mongo.update.useMutation();

View File

@@ -103,7 +103,7 @@ export const AddApplication = ({ projectId, projectName }: Props) => {
projectId, projectId,
}); });
}) })
.catch((e) => { .catch((_e) => {
toast.error("Error creating the service"); toast.error("Error creating the service");
}); });
}; };

View File

@@ -434,14 +434,14 @@ export const AddTemplate = ({ projectId }: Props) => {
}); });
toast.promise(promise, { toast.promise(promise, {
loading: "Setting up...", loading: "Setting up...",
success: (data) => { success: (_data) => {
utils.project.one.invalidate({ utils.project.one.invalidate({
projectId, projectId,
}); });
setOpen(false); setOpen(false);
return `${template.name} template created successfully`; return `${template.name} template created successfully`;
}, },
error: (err) => { error: (_err) => {
return `An error ocurred deploying ${template.name} template`; return `An error ocurred deploying ${template.name} template`;
}, },
}); });

View File

@@ -79,7 +79,7 @@ export const ShowExternalRedisCredentials = ({ redisId }: Props) => {
useEffect(() => { useEffect(() => {
const buildConnectionUrl = () => { const buildConnectionUrl = () => {
const hostname = window.location.hostname; const _hostname = window.location.hostname;
const port = form.watch("externalPort") || data?.externalPort; const port = form.watch("externalPort") || data?.externalPort;
return `redis://default:${data?.databasePassword}@${getIp}:${port}`; return `redis://default:${data?.databasePassword}@${getIp}:${port}`;

View File

@@ -24,7 +24,7 @@ export const getStatusColor = (status: number) => {
export const columns: ColumnDef<LogEntry>[] = [ export const columns: ColumnDef<LogEntry>[] = [
{ {
accessorKey: "level", accessorKey: "level",
header: ({ column }) => { header: () => {
return <Button variant="ghost">Level</Button>; return <Button variant="ghost">Level</Button>;
}, },
cell: ({ row }) => { cell: ({ row }) => {

View File

@@ -92,7 +92,7 @@ export const RequestsTable = () => {
pageSize: 10, pageSize: 10,
}); });
const { data: statsLogs, isLoading } = api.settings.readStatsLogs.useQuery( const { data: statsLogs } = api.settings.readStatsLogs.useQuery(
{ {
sort: sorting[0], sort: sorting[0],
page: pagination, page: pagination,
@@ -300,7 +300,7 @@ export const RequestsTable = () => {
</div> </div>
<Sheet <Sheet
open={!!selectedRow} open={!!selectedRow}
onOpenChange={(open) => setSelectedRow(undefined)} onOpenChange={(_open) => setSelectedRow(undefined)}
> >
<SheetContent className="sm:max-w-[740px] flex flex-col"> <SheetContent className="sm:max-w-[740px] flex flex-col">
<SheetHeader> <SheetHeader>

View File

@@ -22,14 +22,11 @@ import {
extractServices, extractServices,
} from "@/pages/dashboard/project/[projectId]"; } from "@/pages/dashboard/project/[projectId]";
import { api } from "@/utils/api"; import { api } from "@/utils/api";
import type { findProjectById } from "@dokploy/server/services/project";
import { BookIcon, CircuitBoard, GlobeIcon } from "lucide-react"; import { BookIcon, CircuitBoard, GlobeIcon } from "lucide-react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import React from "react"; import React from "react";
import { StatusTooltip } from "../shared/status-tooltip"; import { StatusTooltip } from "../shared/status-tooltip";
type Project = Awaited<ReturnType<typeof findProjectById>>;
export const SearchCommand = () => { export const SearchCommand = () => {
const router = useRouter(); const router = useRouter();
const [open, setOpen] = React.useState(false); const [open, setOpen] = React.useState(false);
@@ -38,7 +35,7 @@ export const SearchCommand = () => {
const { data } = api.project.all.useQuery(undefined, { const { data } = api.project.all.useQuery(undefined, {
enabled: !!session, enabled: !!session,
}); });
const { data: isCloud, isLoading } = api.settings.isCloud.useQuery(); const { data: isCloud } = api.settings.isCloud.useQuery();
React.useEffect(() => { React.useEffect(() => {
const down = (e: KeyboardEvent) => { const down = (e: KeyboardEvent) => {

View File

@@ -38,7 +38,7 @@ export const calculatePrice = (count: number, isAnnual = false) => {
return count * 3.5; return count * 3.5;
}; };
export const ShowBilling = () => { export const ShowBilling = () => {
const { data: servers } = api.server.all.useQuery(undefined); const { data: servers } = api.server.count.useQuery();
const { data: admin } = api.user.get.useQuery(); const { data: admin } = api.user.get.useQuery();
const { data, isLoading } = api.stripe.getProducts.useQuery(); const { data, isLoading } = api.stripe.getProducts.useQuery();
const { mutateAsync: createCheckoutSession } = const { mutateAsync: createCheckoutSession } =
@@ -71,7 +71,7 @@ export const ShowBilling = () => {
}); });
const maxServers = admin?.user.serversQuantity ?? 1; const maxServers = admin?.user.serversQuantity ?? 1;
const percentage = ((servers?.length ?? 0) / maxServers) * 100; const percentage = ((servers ?? 0) / maxServers) * 100;
const safePercentage = Math.min(percentage, 100); const safePercentage = Math.min(percentage, 100);
return ( return (
@@ -102,13 +102,13 @@ export const ShowBilling = () => {
<div className="space-y-2 flex flex-col"> <div className="space-y-2 flex flex-col">
<h3 className="text-lg font-medium">Servers Plan</h3> <h3 className="text-lg font-medium">Servers Plan</h3>
<p className="text-sm text-muted-foreground"> <p className="text-sm text-muted-foreground">
You have {servers?.length} server on your plan of{" "} You have {servers} server on your plan of{" "}
{admin?.user.serversQuantity} servers {admin?.user.serversQuantity} servers
</p> </p>
<div> <div>
<Progress value={safePercentage} className="max-w-lg" /> <Progress value={safePercentage} className="max-w-lg" />
</div> </div>
{admin && admin.user.serversQuantity! <= servers?.length! && ( {admin && admin.user.serversQuantity! <= (servers ?? 0) && (
<div className="flex flex-row gap-4 p-2 bg-yellow-50 dark:bg-yellow-950 rounded-lg items-center"> <div className="flex flex-row gap-4 p-2 bg-yellow-50 dark:bg-yellow-950 rounded-lg items-center">
<AlertTriangle className="text-yellow-600 dark:text-yellow-400" /> <AlertTriangle className="text-yellow-600 dark:text-yellow-400" />
<span className="text-sm text-yellow-600 dark:text-yellow-400"> <span className="text-sm text-yellow-600 dark:text-yellow-400">

View File

@@ -41,8 +41,7 @@ export const ShowNodes = () => {
const { data, isLoading, refetch } = api.cluster.getNodes.useQuery(); const { data, isLoading, refetch } = api.cluster.getNodes.useQuery();
const { data: registry } = api.registry.all.useQuery(); const { data: registry } = api.registry.all.useQuery();
const { mutateAsync: deleteNode, isLoading: isRemoving } = const { mutateAsync: deleteNode } = api.cluster.removeWorker.useMutation();
api.cluster.removeWorker.useMutation();
const haveAtLeastOneRegistry = !!(registry && registry?.length > 0); const haveAtLeastOneRegistry = !!(registry && registry?.length > 0);
return ( return (

View File

@@ -131,7 +131,7 @@ export const HandleRegistry = ({ registryId }: Props) => {
serverId: data.serverId, serverId: data.serverId,
registryId: registryId || "", registryId: registryId || "",
}) })
.then(async (data) => { .then(async (_data) => {
await utils.registry.all.invalidate(); await utils.registry.all.invalidate();
toast.success(registryId ? "Registry updated" : "Registry added"); toast.success(registryId ? "Registry updated" : "Registry added");
setIsOpen(false); setIsOpen(false);

View File

@@ -47,10 +47,10 @@ type Schema = z.infer<typeof Schema>;
export const AddBitbucketProvider = () => { export const AddBitbucketProvider = () => {
const utils = api.useUtils(); const utils = api.useUtils();
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const url = useUrl(); const _url = useUrl();
const { mutateAsync, error, isError } = api.bitbucket.create.useMutation(); const { mutateAsync, error, isError } = api.bitbucket.create.useMutation();
const { data: auth } = api.user.get.useQuery(); const { data: auth } = api.user.get.useQuery();
const router = useRouter(); const _router = useRouter();
const form = useForm<Schema>({ const form = useForm<Schema>({
defaultValues: { defaultValues: {
username: "", username: "",

View File

@@ -102,7 +102,7 @@ export const ShowGitProviders = () => {
</div> </div>
<div className="flex flex-col gap-4 rounded-lg "> <div className="flex flex-col gap-4 rounded-lg ">
{data?.map((gitProvider, index) => { {data?.map((gitProvider, _index) => {
const isGithub = gitProvider.providerType === "github"; const isGithub = gitProvider.providerType === "github";
const isGitlab = gitProvider.providerType === "gitlab"; const isGitlab = gitProvider.providerType === "gitlab";
const isBitbucket = const isBitbucket =

View File

@@ -136,7 +136,7 @@ export const HandleNotifications = ({ notificationId }: Props) => {
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
const { data: isCloud } = api.settings.isCloud.useQuery(); const { data: isCloud } = api.settings.isCloud.useQuery();
const { data: notification, refetch } = api.notification.one.useQuery( const { data: notification } = api.notification.one.useQuery(
{ {
notificationId: notificationId || "", notificationId: notificationId || "",
}, },
@@ -1038,7 +1038,7 @@ export const HandleNotifications = ({ notificationId }: Props) => {
}); });
} }
toast.success("Connection Success"); toast.success("Connection Success");
} catch (err) { } catch (_err) {
toast.error("Error testing the provider"); toast.error("Error testing the provider");
} }
}} }}

View File

@@ -56,7 +56,7 @@ export const ShowNotifications = () => {
) : ( ) : (
<div className="flex flex-col gap-4 min-h-[25vh]"> <div className="flex flex-col gap-4 min-h-[25vh]">
<div className="flex flex-col gap-4 rounded-lg "> <div className="flex flex-col gap-4 rounded-lg ">
{data?.map((notification, index) => ( {data?.map((notification, _index) => (
<div <div
key={notification.notificationId} key={notification.notificationId}
className="flex items-center justify-between bg-sidebar p-1 w-full rounded-lg" className="flex items-center justify-between bg-sidebar p-1 w-full rounded-lg"

View File

@@ -63,7 +63,7 @@ export const Disable2FA = () => {
toast.success("2FA disabled successfully"); toast.success("2FA disabled successfully");
utils.auth.get.invalidate(); utils.auth.get.invalidate();
setIsOpen(false); setIsOpen(false);
} catch (error) { } catch (_error) {
form.setError("password", { form.setError("password", {
message: "Connection error. Please try again.", message: "Connection error. Please try again.",
}); });

View File

@@ -47,20 +47,8 @@ const PinSchema = z.object({
type PasswordForm = z.infer<typeof PasswordSchema>; type PasswordForm = z.infer<typeof PasswordSchema>;
type PinForm = z.infer<typeof PinSchema>; type PinForm = z.infer<typeof PinSchema>;
type TwoFactorEnableResponse = {
totpURI: string;
backupCodes: string[];
};
type TwoFactorSetupData = {
qrCodeUrl: string;
secret: string;
totpURI: string;
};
export const Enable2FA = () => { export const Enable2FA = () => {
const utils = api.useUtils(); const utils = api.useUtils();
const { data: session } = authClient.useSession();
const [data, setData] = useState<TwoFactorSetupData | null>(null); const [data, setData] = useState<TwoFactorSetupData | null>(null);
const [backupCodes, setBackupCodes] = useState<string[]>([]); const [backupCodes, setBackupCodes] = useState<string[]>([]);
const [isDialogOpen, setIsDialogOpen] = useState(false); const [isDialogOpen, setIsDialogOpen] = useState(false);

View File

@@ -54,9 +54,7 @@ const randomImages = [
]; ];
export const ProfileForm = () => { export const ProfileForm = () => {
const utils = api.useUtils(); const _utils = api.useUtils();
const { mutateAsync: disable2FA, isLoading: isDisabling } =
api.auth.disable2FA.useMutation();
const { data, refetch, isLoading } = api.user.get.useQuery(); const { data, refetch, isLoading } = api.user.get.useQuery();
const { const {
mutateAsync, mutateAsync,

View File

@@ -26,7 +26,7 @@ export const ShowStorageActions = ({ serverId }: Props) => {
isLoading: cleanDockerBuilderIsLoading, isLoading: cleanDockerBuilderIsLoading,
} = api.settings.cleanDockerBuilder.useMutation(); } = api.settings.cleanDockerBuilder.useMutation();
const { mutateAsync: cleanMonitoring, isLoading: cleanMonitoringIsLoading } = const { mutateAsync: cleanMonitoring } =
api.settings.cleanMonitoring.useMutation(); api.settings.cleanMonitoring.useMutation();
const { const {
mutateAsync: cleanUnusedImages, mutateAsync: cleanUnusedImages,

View File

@@ -36,7 +36,7 @@ export const ToggleDockerCleanup = ({ serverId }: Props) => {
await refetch(); await refetch();
} }
toast.success("Docker Cleanup updated"); toast.success("Docker Cleanup updated");
} catch (error) { } catch (_error) {
toast.error("Docker Cleanup Error"); toast.error("Docker Cleanup Error");
} }
}; };

View File

@@ -82,7 +82,7 @@ export const EditScript = ({ serverId }: Props) => {
command: formData.command || "", command: formData.command || "",
serverId, serverId,
}) })
.then((data) => { .then((_data) => {
toast.success("Script modified successfully"); toast.success("Script modified successfully");
}) })
.catch(() => { .catch(() => {

View File

@@ -56,7 +56,7 @@ export function GPUSupport({ serverId }: GPUSupportProps) {
try { try {
await utils.settings.checkGPUStatus.invalidate({ serverId }); await utils.settings.checkGPUStatus.invalidate({ serverId });
await refetch(); await refetch();
} catch (error) { } catch (_error) {
toast.error("Failed to refresh GPU status"); toast.error("Failed to refresh GPU status");
} finally { } finally {
setIsRefreshing(false); setIsRefreshing(false);
@@ -74,7 +74,7 @@ export function GPUSupport({ serverId }: GPUSupportProps) {
try { try {
await setupGPU.mutateAsync({ serverId }); await setupGPU.mutateAsync({ serverId });
} catch (error) { } catch (_error) {
// Error handling is done in mutation's onError // Error handling is done in mutation's onError
} }
}; };

View File

@@ -118,7 +118,7 @@ export const HandleServers = ({ serverId }: Props) => {
sshKeyId: data.sshKeyId || "", sshKeyId: data.sshKeyId || "",
serverId: serverId || "", serverId: serverId || "",
}) })
.then(async (data) => { .then(async (_data) => {
await utils.server.all.invalidate(); await utils.server.all.invalidate();
refetchServer(); refetchServer();
toast.success(serverId ? "Server Updated" : "Server Created"); toast.success(serverId ? "Server Updated" : "Server Created");

View File

@@ -25,7 +25,7 @@ export const SecurityAudit = ({ serverId }: Props) => {
enabled: !!serverId, enabled: !!serverId,
}, },
); );
const utils = api.useUtils(); const _utils = api.useUtils();
return ( return (
<CardContent className="p-0"> <CardContent className="p-0">
<div className="flex flex-col gap-4"> <div className="flex flex-col gap-4">

View File

@@ -80,7 +80,7 @@ const Schema = z.object({
type Schema = z.infer<typeof Schema>; type Schema = z.infer<typeof Schema>;
export const SetupMonitoring = ({ serverId }: Props) => { export const SetupMonitoring = ({ serverId }: Props) => {
const { data, isLoading } = serverId const { data } = serverId
? api.server.one.useQuery( ? api.server.one.useQuery(
{ {
serverId: serverId || "", serverId: serverId || "",

View File

@@ -25,7 +25,7 @@ export const ValidateServer = ({ serverId }: Props) => {
enabled: !!serverId, enabled: !!serverId,
}, },
); );
const utils = api.useUtils(); const _utils = api.useUtils();
return ( return (
<CardContent className="p-0"> <CardContent className="p-0">
<div className="flex flex-col gap-4"> <div className="flex flex-col gap-4">

View File

@@ -52,10 +52,10 @@ interface Props {
export const CreateServer = ({ stepper }: Props) => { export const CreateServer = ({ stepper }: Props) => {
const { data: sshKeys } = api.sshKey.all.useQuery(); const { data: sshKeys } = api.sshKey.all.useQuery();
const [isOpen, setIsOpen] = useState(false); const [isOpen, _setIsOpen] = useState(false);
const { data: canCreateMoreServers, refetch } = const { data: canCreateMoreServers, refetch } =
api.stripe.canCreateMoreServers.useQuery(); api.stripe.canCreateMoreServers.useQuery();
const { mutateAsync, error, isError } = api.server.create.useMutation(); const { mutateAsync } = api.server.create.useMutation();
const cloudSSHKey = sshKeys?.find( const cloudSSHKey = sshKeys?.find(
(sshKey) => sshKey.name === "dokploy-cloud-ssh-key", (sshKey) => sshKey.name === "dokploy-cloud-ssh-key",
); );
@@ -96,7 +96,7 @@ export const CreateServer = ({ stepper }: Props) => {
username: data.username || "root", username: data.username || "root",
sshKeyId: data.sshKeyId || "", sshKeyId: data.sshKeyId || "",
}) })
.then(async (data) => { .then(async (_data) => {
toast.success("Server Created"); toast.success("Server Created");
stepper.next(); stepper.next();
}) })

View File

@@ -37,15 +37,6 @@ export const Verify = () => {
); );
const [isRefreshing, setIsRefreshing] = useState(false); const [isRefreshing, setIsRefreshing] = useState(false);
const { data: server } = api.server.one.useQuery(
{
serverId,
},
{
enabled: !!serverId,
},
);
return ( return (
<CardContent className="p-0"> <CardContent className="p-0">
<div className="flex flex-col gap-4"> <div className="flex flex-col gap-4">

View File

@@ -143,7 +143,7 @@ export const ShowInvitations = () => {
{invitation.status === "pending" && ( {invitation.status === "pending" && (
<DropdownMenuItem <DropdownMenuItem
className="w-full cursor-pointer" className="w-full cursor-pointer"
onSelect={(e) => { onSelect={(_e) => {
copy( copy(
`${origin}/invitation?token=${invitation.id}`, `${origin}/invitation?token=${invitation.id}`,
); );
@@ -159,7 +159,7 @@ export const ShowInvitations = () => {
{invitation.status === "pending" && ( {invitation.status === "pending" && (
<DropdownMenuItem <DropdownMenuItem
className="w-full cursor-pointer" className="w-full cursor-pointer"
onSelect={async (e) => { onSelect={async (_e) => {
const result = const result =
await authClient.organization.cancelInvitation( await authClient.organization.cancelInvitation(
{ {

View File

@@ -35,7 +35,7 @@ import { AddUserPermissions } from "./add-permissions";
export const ShowUsers = () => { export const ShowUsers = () => {
const { data: isCloud } = api.settings.isCloud.useQuery(); const { data: isCloud } = api.settings.isCloud.useQuery();
const { data, isLoading, refetch } = api.user.all.useQuery(); const { data, isLoading, refetch } = api.user.all.useQuery();
const { mutateAsync, isLoading: isRemoving } = api.user.remove.useMutation(); const { mutateAsync } = api.user.remove.useMutation();
return ( return (
<div className="w-full"> <div className="w-full">

View File

@@ -14,10 +14,7 @@ import { ShowTraefikActions } from "./servers/actions/show-traefik-actions";
import { ToggleDockerCleanup } from "./servers/actions/toggle-docker-cleanup"; import { ToggleDockerCleanup } from "./servers/actions/toggle-docker-cleanup";
import { UpdateServer } from "./web-server/update-server"; import { UpdateServer } from "./web-server/update-server";
interface Props { export const WebServer = () => {
className?: string;
}
export const WebServer = ({ className }: Props) => {
const { t } = useTranslation("settings"); const { t } = useTranslation("settings");
const { data } = api.user.get.useQuery(); const { data } = api.user.get.useQuery();

View File

@@ -99,7 +99,7 @@ export const ManageTraefikPorts = ({ children, serverId }: Props) => {
}); });
toast.success(t("settings.server.webServer.traefik.portsUpdated")); toast.success(t("settings.server.webServer.traefik.portsUpdated"));
setOpen(false); setOpen(false);
} catch (error) { } catch (_error) {
toast.error(t("settings.server.webServer.traefik.portsUpdateError")); toast.error(t("settings.server.webServer.traefik.portsUpdateError"));
} }
}; };

View File

@@ -43,7 +43,7 @@ interface Props {
serverId?: string; serverId?: string;
} }
export const UpdateServerIp = ({ children, serverId }: Props) => { export const UpdateServerIp = ({ children }: Props) => {
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const { data } = api.user.get.useQuery(); const { data } = api.user.get.useQuery();

View File

@@ -214,7 +214,7 @@ export const columns: ColumnDef<ApplicationList>[] = [
{ {
accessorKey: "Logs", accessorKey: "Logs",
accessorFn: (row) => row.Error, accessorFn: (row) => row.Error,
header: ({ column }) => { header: () => {
return <span>Logs</span>; return <span>Logs</span>;
}, },
cell: ({ row }) => { cell: ({ row }) => {

View File

@@ -48,7 +48,7 @@ export function DataTable<TData, TValue>({
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
React.useState<VisibilityState>({}); React.useState<VisibilityState>({});
const [rowSelection, setRowSelection] = React.useState({}); const [rowSelection, setRowSelection] = React.useState({});
const [pagination, setPagination] = React.useState({ const [_pagination, _setPagination] = React.useState({
pageIndex: 0, //initial page index pageIndex: 0, //initial page index
pageSize: 8, //default page size pageSize: 8, //default page size
}); });

View File

@@ -17,7 +17,7 @@ interface Props {
} }
export const ShowNodeConfig = ({ nodeId, serverId }: Props) => { export const ShowNodeConfig = ({ nodeId, serverId }: Props) => {
const { data, isLoading } = api.swarm.getNodeInfo.useQuery({ const { data } = api.swarm.getNodeInfo.useQuery({
nodeId, nodeId,
serverId, serverId,
}); });

View File

@@ -157,7 +157,7 @@ const MENU: Menu = {
url: "/dashboard/monitoring", url: "/dashboard/monitoring",
icon: BarChartHorizontalBigIcon, icon: BarChartHorizontalBigIcon,
// Only enabled in non-cloud environments // Only enabled in non-cloud environments
isEnabled: ({ auth, isCloud }) => !isCloud, isEnabled: ({ isCloud }) => !isCloud,
}, },
{ {
isSingle: true, isSingle: true,
@@ -277,7 +277,7 @@ const MENU: Menu = {
url: "/dashboard/settings/servers", url: "/dashboard/settings/servers",
icon: Server, icon: Server,
// Only enabled for admins // Only enabled for admins
isEnabled: ({ auth, isCloud }) => !!(auth?.role === "owner"), isEnabled: ({ auth }) => !!(auth?.role === "owner"),
}, },
{ {
isSingle: true, isSingle: true,
@@ -490,8 +490,9 @@ function SidebarLogo() {
const { state } = useSidebar(); const { state } = useSidebar();
const { data: isCloud } = api.settings.isCloud.useQuery(); const { data: isCloud } = api.settings.isCloud.useQuery();
const { data: user } = api.user.get.useQuery(); const { data: user } = api.user.get.useQuery();
const { data: dokployVersion } = api.settings.getDokployVersion.useQuery(); // const { data: dokployVersion } = api.settings.getDokployVersion.useQuery();
const { data: session } = authClient.useSession(); const { data: session } = authClient.useSession();
const { const {
data: organizations, data: organizations,
refetch, refetch,
@@ -501,12 +502,12 @@ function SidebarLogo() {
api.organization.delete.useMutation(); api.organization.delete.useMutation();
const { isMobile } = useSidebar(); const { isMobile } = useSidebar();
const { data: activeOrganization } = authClient.useActiveOrganization(); const { data: activeOrganization } = authClient.useActiveOrganization();
const utils = api.useUtils(); const _utils = api.useUtils();
const { data: invitations, refetch: refetchInvitations } = const { data: invitations, refetch: refetchInvitations } =
api.user.getInvitations.useQuery(); api.user.getInvitations.useQuery();
const [activeTeam, setActiveTeam] = useState< const [_activeTeam, setActiveTeam] = useState<
typeof activeOrganization | null typeof activeOrganization | null
>(null); >(null);
@@ -543,7 +544,7 @@ function SidebarLogo() {
</div> </div>
<div className="flex flex-col items-start"> <div className="flex flex-col items-start">
<p className="text-sm font-medium leading-none"> <p className="text-sm font-medium leading-none">
{activeOrganization?.name} {activeOrganization?.name ?? "Select Organization"}
</p> </p>
</div> </div>
</div> </div>
@@ -551,7 +552,7 @@ function SidebarLogo() {
</SidebarMenuButton> </SidebarMenuButton>
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent <DropdownMenuContent
className="w-[--radix-dropdown-menu-trigger-width] min-w-64 rounded-lg" className=" rounded-lg"
align="start" align="start"
side={isMobile ? "bottom" : "right"} side={isMobile ? "bottom" : "right"}
sideOffset={4} sideOffset={4}
@@ -570,6 +571,7 @@ function SidebarLogo() {
}} }}
className="w-full gap-2 p-2" className="w-full gap-2 p-2"
> >
<div className="flex flex-col gap-4">{org.name}</div>
<div className="flex size-6 items-center justify-center rounded-sm border"> <div className="flex size-6 items-center justify-center rounded-sm border">
<Logo <Logo
className={cn( className={cn(
@@ -578,9 +580,8 @@ function SidebarLogo() {
)} )}
/> />
</div> </div>
{org.name}
</DropdownMenuItem> </DropdownMenuItem>
{(org.ownerId === session?.user?.id || isCloud) && ( {org.ownerId === session?.user?.id && (
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<AddOrganization organizationId={org.id} /> <AddOrganization organizationId={org.id} />
<DialogAction <DialogAction
@@ -618,7 +619,7 @@ function SidebarLogo() {
)} )}
</div> </div>
))} ))}
{!isCloud && user?.role === "owner" && ( {(user?.role === "owner" || isCloud) && (
<> <>
<DropdownMenuSeparator /> <DropdownMenuSeparator />
<AddOrganization /> <AddOrganization />
@@ -721,11 +722,11 @@ export default function Page({ children }: Props) {
const router = useRouter(); const router = useRouter();
const pathname = usePathname(); const pathname = usePathname();
const currentPath = router.pathname; const _currentPath = router.pathname;
const { data: auth } = api.user.get.useQuery(); const { data: auth } = api.user.get.useQuery();
const includesProjects = pathname?.includes("/dashboard/project"); const includesProjects = pathname?.includes("/dashboard/project");
const { data: isCloud, isLoading } = api.settings.isCloud.useQuery(); const { data: isCloud } = api.settings.isCloud.useQuery();
const { const {
home: filteredHome, home: filteredHome,

View File

@@ -11,7 +11,7 @@ export const UpdateServerButton = () => {
latestVersion: null, latestVersion: null,
updateAvailable: false, updateAvailable: false,
}); });
const router = useRouter(); const _router = useRouter();
const { data: isCloud } = api.settings.isCloud.useQuery(); const { data: isCloud } = api.settings.isCloud.useQuery();
const { mutateAsync: getUpdateData } = const { mutateAsync: getUpdateData } =
api.settings.getUpdateData.useMutation(); api.settings.getUpdateData.useMutation();

View File

@@ -24,7 +24,7 @@ import { useRouter } from "next/router";
import { ModeToggle } from "../ui/modeToggle"; import { ModeToggle } from "../ui/modeToggle";
import { SidebarMenuButton } from "../ui/sidebar"; import { SidebarMenuButton } from "../ui/sidebar";
const AUTO_CHECK_UPDATES_INTERVAL_MINUTES = 7; const _AUTO_CHECK_UPDATES_INTERVAL_MINUTES = 7;
export const UserNav = () => { export const UserNav = () => {
const router = useRouter(); const router = useRouter();

View File

@@ -26,7 +26,7 @@ export const BreadcrumbSidebar = ({ list }: Props) => {
<Separator orientation="vertical" className="mr-2 h-4" /> <Separator orientation="vertical" className="mr-2 h-4" />
<Breadcrumb> <Breadcrumb>
<BreadcrumbList> <BreadcrumbList>
{list.map((item, index) => ( {list.map((item, _index) => (
<Fragment key={item.name}> <Fragment key={item.name}>
<BreadcrumbItem className="block"> <BreadcrumbItem className="block">
<BreadcrumbLink href={item.href} asChild={!!item.href}> <BreadcrumbLink href={item.href} asChild={!!item.href}>

View File

@@ -43,7 +43,7 @@ export const DrawerLogs = ({ isOpen, onClose, filteredLogs }: Props) => {
return ( return (
<Sheet <Sheet
open={!!isOpen} open={!!isOpen}
onOpenChange={(open) => { onOpenChange={(_open) => {
onClose(); onClose();
}} }}
> >

View File

@@ -85,7 +85,7 @@ const Tree = React.forwardRef<HTMLDivElement, TreeProps>(
return ids; return ids;
}, [data, initialSlelectedItemId]); }, [data, initialSlelectedItemId]);
const { ref: refRoot, width, height } = useResizeObserver(); const { ref: refRoot } = useResizeObserver();
return ( return (
<div ref={refRoot} className={cn("overflow-y-auto", className)}> <div ref={refRoot} className={cn("overflow-y-auto", className)}>

View File

@@ -136,7 +136,7 @@ await db
}, },
}); });
for (const project of projects) { for (const project of projects) {
const user = await db.update(schema.projects).set({ const _user = await db.update(schema.projects).set({
organizationId: project.user.organizations[0]?.id || "", organizationId: project.user.organizations[0]?.id || "",
}); });
} }

View File

@@ -90,7 +90,7 @@ export default function Custom404({ statusCode, error }: Props) {
} }
// @ts-ignore // @ts-ignore
Error.getInitialProps = ({ res, err, ...rest }: NextPageContext) => { Error.getInitialProps = ({ res, err }: NextPageContext) => {
const statusCode = res ? res.statusCode : err ? err.statusCode : 404; const statusCode = res ? res.statusCode : err ? err.statusCode : 404;
return { statusCode, error: err }; return { statusCode, error: err };
}; };

View File

@@ -1,7 +1,7 @@
import type { NextApiRequest, NextApiResponse } from "next"; import type { NextApiRequest, NextApiResponse } from "next";
export default async function handler( export default async function handler(
req: NextApiRequest, _req: NextApiRequest,
res: NextApiResponse, res: NextApiResponse,
) { ) {
return res.status(200).json({ ok: true }); return res.status(200).json({ ok: true });

View File

@@ -16,8 +16,7 @@ export default async function handler(
req: NextApiRequest, req: NextApiRequest,
res: NextApiResponse, res: NextApiResponse,
) { ) {
const { code, state, installation_id, setup_action }: Query = const { code, state, installation_id }: Query = req.query as Query;
req.query as Query;
if (!code) { if (!code) {
return res.status(400).json({ error: "Missing code parameter" }); return res.status(400).json({ error: "Missing code parameter" });

View File

@@ -1,7 +1,7 @@
import { buffer } from "node:stream/consumers"; import { buffer } from "node:stream/consumers";
import { db } from "@/server/db"; import { db } from "@/server/db";
import { server, users_temp } from "@/server/db/schema"; import { organization, server, users_temp } from "@/server/db/schema";
import { findUserById } from "@dokploy/server"; import { findUserById, type Server } from "@dokploy/server";
import { asc, eq } from "drizzle-orm"; import { asc, eq } from "drizzle-orm";
import type { NextApiRequest, NextApiResponse } from "next"; import type { NextApiRequest, NextApiResponse } from "next";
import Stripe from "stripe"; import Stripe from "stripe";
@@ -172,11 +172,11 @@ export default async function handler(
} }
await db await db
.update(admins) .update(users_temp)
.set({ .set({
serversQuantity: suscription?.items?.data?.[0]?.quantity ?? 0, serversQuantity: suscription?.items?.data?.[0]?.quantity ?? 0,
}) })
.where(eq(admins.stripeCustomerId, suscription.customer as string)); .where(eq(users_temp.stripeCustomerId, suscription.customer as string));
const admin = await findUserByStripeCustomerId( const admin = await findUserByStripeCustomerId(
suscription.customer as string, suscription.customer as string,
@@ -205,11 +205,13 @@ export default async function handler(
return res.status(400).send("Webhook Error: Admin not found"); return res.status(400).send("Webhook Error: Admin not found");
} }
await db await db
.update(admins) .update(users_temp)
.set({ .set({
serversQuantity: 0, serversQuantity: 0,
}) })
.where(eq(admins.stripeCustomerId, newInvoice.customer as string)); .where(
eq(users_temp.stripeCustomerId, newInvoice.customer as string),
);
await disableServers(admin.id); await disableServers(admin.id);
} }
@@ -245,12 +247,18 @@ export default async function handler(
} }
const disableServers = async (userId: string) => { const disableServers = async (userId: string) => {
await db const organizations = await db.query.organization.findMany({
.update(server) where: eq(organization.ownerId, userId),
.set({ });
serverStatus: "inactive",
}) for (const org of organizations) {
.where(eq(server.userId, userId)); await db
.update(server)
.set({
serverStatus: "inactive",
})
.where(eq(server.organizationId, org.id));
}
}; };
const findUserByStripeCustomerId = async (stripeCustomerId: string) => { const findUserByStripeCustomerId = async (stripeCustomerId: string) => {
@@ -275,11 +283,19 @@ const deactivateServer = async (serverId: string) => {
}; };
export const findServersByUserIdSorted = async (userId: string) => { export const findServersByUserIdSorted = async (userId: string) => {
const servers = await db.query.server.findMany({ const organizations = await db.query.organization.findMany({
where: eq(server.userId, userId), where: eq(organization.ownerId, userId),
orderBy: asc(server.createdAt),
}); });
const servers: Server[] = [];
for (const org of organizations) {
const serversByOrg = await db.query.server.findMany({
where: eq(server.organizationId, org.id),
orderBy: asc(server.createdAt),
});
servers.push(...serversByOrg);
}
return servers; return servers;
}; };
export const updateServersBasedOnQuantity = async ( export const updateServersBasedOnQuantity = async (

View File

@@ -72,7 +72,7 @@ export async function getServerSideProps(
trpcState: helpers.dehydrate(), trpcState: helpers.dehydrate(),
}, },
}; };
} catch (error) { } catch (_error) {
return { return {
props: {}, props: {},
}; };

View File

@@ -15,8 +15,7 @@ const BASE_URL = "http://localhost:3001/metrics";
const DEFAULT_TOKEN = "metrics"; const DEFAULT_TOKEN = "metrics";
const Dashboard = () => { const Dashboard = () => {
const { data: isCloud } = api.settings.isCloud.useQuery(); const [toggleMonitoring, _setToggleMonitoring] = useLocalStorage(
const [toggleMonitoring, setToggleMonitoring] = useLocalStorage(
"monitoring-enabled", "monitoring-enabled",
false, false,
); );

View File

@@ -261,7 +261,7 @@ const Project = (
try { try {
await composeActions.start.mutateAsync({ composeId: serviceId }); await composeActions.start.mutateAsync({ composeId: serviceId });
success++; success++;
} catch (error) { } catch (_error) {
toast.error(`Error starting service ${serviceId}`); toast.error(`Error starting service ${serviceId}`);
} }
} }
@@ -281,7 +281,7 @@ const Project = (
try { try {
await composeActions.stop.mutateAsync({ composeId: serviceId }); await composeActions.stop.mutateAsync({ composeId: serviceId });
success++; success++;
} catch (error) { } catch (_error) {
toast.error(`Error stopping service ${serviceId}`); toast.error(`Error stopping service ${serviceId}`);
} }
} }
@@ -685,7 +685,7 @@ export async function getServerSideProps(
projectId: params?.projectId, projectId: params?.projectId,
}, },
}; };
} catch (error) { } catch (_error) {
return { return {
redirect: { redirect: {
permanent: false, permanent: false,

View File

@@ -65,7 +65,7 @@ type TabState =
const Service = ( const Service = (
props: InferGetServerSidePropsType<typeof getServerSideProps>, props: InferGetServerSidePropsType<typeof getServerSideProps>,
) => { ) => {
const [toggleMonitoring, setToggleMonitoring] = useState(false); const [_toggleMonitoring, _setToggleMonitoring] = useState(false);
const { applicationId, activeTab } = props; const { applicationId, activeTab } = props;
const router = useRouter(); const router = useRouter();
const { projectId } = router.query; const { projectId } = router.query;
@@ -86,7 +86,6 @@ const Service = (
const { data: isCloud } = api.settings.isCloud.useQuery(); const { data: isCloud } = api.settings.isCloud.useQuery();
const { data: auth } = api.user.get.useQuery(); const { data: auth } = api.user.get.useQuery();
const { data: monitoring } = api.user.getMetricsToken.useQuery();
return ( return (
<div className="pb-10"> <div className="pb-10">
@@ -399,7 +398,7 @@ export async function getServerSideProps(
activeTab: (activeTab || "general") as TabState, activeTab: (activeTab || "general") as TabState,
}, },
}; };
} catch (error) { } catch (_error) {
return { return {
redirect: { redirect: {
permanent: false, permanent: false,

View File

@@ -59,7 +59,7 @@ type TabState =
const Service = ( const Service = (
props: InferGetServerSidePropsType<typeof getServerSideProps>, props: InferGetServerSidePropsType<typeof getServerSideProps>,
) => { ) => {
const [toggleMonitoring, setToggleMonitoring] = useState(false); const [_toggleMonitoring, _setToggleMonitoring] = useState(false);
const { composeId, activeTab } = props; const { composeId, activeTab } = props;
const router = useRouter(); const router = useRouter();
const { projectId } = router.query; const { projectId } = router.query;
@@ -79,7 +79,6 @@ const Service = (
); );
const { data: auth } = api.user.get.useQuery(); const { data: auth } = api.user.get.useQuery();
const { data: monitoring } = api.user.getMetricsToken.useQuery();
const { data: isCloud } = api.settings.isCloud.useQuery(); const { data: isCloud } = api.settings.isCloud.useQuery();
return ( return (
@@ -393,7 +392,7 @@ export async function getServerSideProps(
activeTab: (activeTab || "general") as TabState, activeTab: (activeTab || "general") as TabState,
}, },
}; };
} catch (error) { } catch (_error) {
return { return {
redirect: { redirect: {
permanent: false, permanent: false,

View File

@@ -52,7 +52,7 @@ type TabState = "projects" | "monitoring" | "settings" | "backups" | "advanced";
const Mariadb = ( const Mariadb = (
props: InferGetServerSidePropsType<typeof getServerSideProps>, props: InferGetServerSidePropsType<typeof getServerSideProps>,
) => { ) => {
const [toggleMonitoring, setToggleMonitoring] = useState(false); const [_toggleMonitoring, _setToggleMonitoring] = useState(false);
const { mariadbId, activeTab } = props; const { mariadbId, activeTab } = props;
const router = useRouter(); const router = useRouter();
@@ -60,7 +60,6 @@ const Mariadb = (
const [tab, setSab] = useState<TabState>(activeTab); const [tab, setSab] = useState<TabState>(activeTab);
const { data } = api.mariadb.one.useQuery({ mariadbId }); const { data } = api.mariadb.one.useQuery({ mariadbId });
const { data: auth } = api.user.get.useQuery(); const { data: auth } = api.user.get.useQuery();
const { data: monitoring } = api.user.getMetricsToken.useQuery();
const { data: isCloud } = api.settings.isCloud.useQuery(); const { data: isCloud } = api.settings.isCloud.useQuery();
@@ -342,7 +341,7 @@ export async function getServerSideProps(
activeTab: (activeTab || "general") as TabState, activeTab: (activeTab || "general") as TabState,
}, },
}; };
} catch (error) { } catch (_error) {
return { return {
redirect: { redirect: {
permanent: false, permanent: false,

View File

@@ -52,7 +52,7 @@ type TabState = "projects" | "monitoring" | "settings" | "backups" | "advanced";
const Mongo = ( const Mongo = (
props: InferGetServerSidePropsType<typeof getServerSideProps>, props: InferGetServerSidePropsType<typeof getServerSideProps>,
) => { ) => {
const [toggleMonitoring, setToggleMonitoring] = useState(false); const [_toggleMonitoring, _setToggleMonitoring] = useState(false);
const { mongoId, activeTab } = props; const { mongoId, activeTab } = props;
const router = useRouter(); const router = useRouter();
const { projectId } = router.query; const { projectId } = router.query;
@@ -60,7 +60,6 @@ const Mongo = (
const { data } = api.mongo.one.useQuery({ mongoId }); const { data } = api.mongo.one.useQuery({ mongoId });
const { data: auth } = api.user.get.useQuery(); const { data: auth } = api.user.get.useQuery();
const { data: monitoring } = api.user.getMetricsToken.useQuery();
const { data: isCloud } = api.settings.isCloud.useQuery(); const { data: isCloud } = api.settings.isCloud.useQuery();
@@ -343,7 +342,7 @@ export async function getServerSideProps(
activeTab: (activeTab || "general") as TabState, activeTab: (activeTab || "general") as TabState,
}, },
}; };
} catch (error) { } catch (_error) {
return { return {
redirect: { redirect: {
permanent: false, permanent: false,

View File

@@ -52,14 +52,13 @@ type TabState = "projects" | "monitoring" | "settings" | "backups" | "advanced";
const MySql = ( const MySql = (
props: InferGetServerSidePropsType<typeof getServerSideProps>, props: InferGetServerSidePropsType<typeof getServerSideProps>,
) => { ) => {
const [toggleMonitoring, setToggleMonitoring] = useState(false); const [_toggleMonitoring, _setToggleMonitoring] = useState(false);
const { mysqlId, activeTab } = props; const { mysqlId, activeTab } = props;
const router = useRouter(); const router = useRouter();
const { projectId } = router.query; const { projectId } = router.query;
const [tab, setSab] = useState<TabState>(activeTab); const [tab, setSab] = useState<TabState>(activeTab);
const { data } = api.mysql.one.useQuery({ mysqlId }); const { data } = api.mysql.one.useQuery({ mysqlId });
const { data: auth } = api.user.get.useQuery(); const { data: auth } = api.user.get.useQuery();
const { data: monitoring } = api.user.getMetricsToken.useQuery();
const { data: isCloud } = api.settings.isCloud.useQuery(); const { data: isCloud } = api.settings.isCloud.useQuery();
@@ -348,7 +347,7 @@ export async function getServerSideProps(
activeTab: (activeTab || "general") as TabState, activeTab: (activeTab || "general") as TabState,
}, },
}; };
} catch (error) { } catch (_error) {
return { return {
redirect: { redirect: {
permanent: false, permanent: false,

View File

@@ -52,7 +52,7 @@ type TabState = "projects" | "monitoring" | "settings" | "backups" | "advanced";
const Postgresql = ( const Postgresql = (
props: InferGetServerSidePropsType<typeof getServerSideProps>, props: InferGetServerSidePropsType<typeof getServerSideProps>,
) => { ) => {
const [toggleMonitoring, setToggleMonitoring] = useState(false); const [_toggleMonitoring, _setToggleMonitoring] = useState(false);
const { postgresId, activeTab } = props; const { postgresId, activeTab } = props;
const router = useRouter(); const router = useRouter();
const { projectId } = router.query; const { projectId } = router.query;
@@ -60,7 +60,6 @@ const Postgresql = (
const { data } = api.postgres.one.useQuery({ postgresId }); const { data } = api.postgres.one.useQuery({ postgresId });
const { data: auth } = api.user.get.useQuery(); const { data: auth } = api.user.get.useQuery();
const { data: monitoring } = api.user.getMetricsToken.useQuery();
const { data: isCloud } = api.settings.isCloud.useQuery(); const { data: isCloud } = api.settings.isCloud.useQuery();
return ( return (
@@ -345,7 +344,7 @@ export async function getServerSideProps(
activeTab: (activeTab || "general") as TabState, activeTab: (activeTab || "general") as TabState,
}, },
}; };
} catch (error) { } catch (_error) {
return { return {
redirect: { redirect: {
permanent: false, permanent: false,

View File

@@ -51,7 +51,7 @@ type TabState = "projects" | "monitoring" | "settings" | "advanced";
const Redis = ( const Redis = (
props: InferGetServerSidePropsType<typeof getServerSideProps>, props: InferGetServerSidePropsType<typeof getServerSideProps>,
) => { ) => {
const [toggleMonitoring, setToggleMonitoring] = useState(false); const [_toggleMonitoring, _setToggleMonitoring] = useState(false);
const { redisId, activeTab } = props; const { redisId, activeTab } = props;
const router = useRouter(); const router = useRouter();
const { projectId } = router.query; const { projectId } = router.query;
@@ -59,7 +59,6 @@ const Redis = (
const { data } = api.redis.one.useQuery({ redisId }); const { data } = api.redis.one.useQuery({ redisId });
const { data: auth } = api.user.get.useQuery(); const { data: auth } = api.user.get.useQuery();
const { data: monitoring } = api.user.getMetricsToken.useQuery();
const { data: isCloud } = api.settings.isCloud.useQuery(); const { data: isCloud } = api.settings.isCloud.useQuery();
@@ -335,7 +334,7 @@ export async function getServerSideProps(
activeTab: (activeTab || "general") as TabState, activeTab: (activeTab || "general") as TabState,
}, },
}; };
} catch (error) { } catch (_error) {
return { return {
redirect: { redirect: {
permanent: false, permanent: false,

View File

@@ -68,7 +68,7 @@ export async function getServerSideProps(
trpcState: helpers.dehydrate(), trpcState: helpers.dehydrate(),
}, },
}; };
} catch (error) { } catch (_error) {
return { return {
props: {}, props: {},
}; };

View File

@@ -33,7 +33,7 @@ export async function getServerSideProps(
}, },
}; };
} }
const { req, res, resolvedUrl } = ctx; const { req, res } = ctx;
const helpers = createServerSideHelpers({ const helpers = createServerSideHelpers({
router: appRouter, router: appRouter,
ctx: { ctx: {
@@ -69,7 +69,7 @@ export async function getServerSideProps(
trpcState: helpers.dehydrate(), trpcState: helpers.dehydrate(),
}, },
}; };
} catch (error) { } catch (_error) {
return { return {
props: {}, props: {},
}; };

View File

@@ -72,7 +72,7 @@ export async function getServerSideProps(
trpcState: helpers.dehydrate(), trpcState: helpers.dehydrate(),
}, },
}; };
} catch (error) { } catch (_error) {
return { return {
props: {}, props: {},
}; };

View File

@@ -72,7 +72,7 @@ export async function getServerSideProps(
trpcState: helpers.dehydrate(), trpcState: helpers.dehydrate(),
}, },
}; };
} catch (error) { } catch (_error) {
return { return {
props: {}, props: {},
}; };

View File

@@ -43,18 +43,11 @@ const LoginSchema = z.object({
password: z.string().min(8), password: z.string().min(8),
}); });
const TwoFactorSchema = z.object({ const _TwoFactorSchema = z.object({
code: z.string().min(6), code: z.string().min(6),
}); });
const BackupCodeSchema = z.object({
code: z.string().min(8, {
message: "Backup code must be at least 8 characters",
}),
});
type LoginForm = z.infer<typeof LoginSchema>; type LoginForm = z.infer<typeof LoginSchema>;
type BackupCodeForm = z.infer<typeof BackupCodeSchema>;
interface Props { interface Props {
IS_CLOUD: boolean; IS_CLOUD: boolean;
@@ -101,7 +94,7 @@ export default function Home({ IS_CLOUD }: Props) {
toast.success("Logged in successfully"); toast.success("Logged in successfully");
router.push("/dashboard/projects"); router.push("/dashboard/projects");
} catch (error) { } catch (_error) {
toast.error("An error occurred while logging in"); toast.error("An error occurred while logging in");
} finally { } finally {
setIsLoginLoading(false); setIsLoginLoading(false);
@@ -117,7 +110,7 @@ export default function Home({ IS_CLOUD }: Props) {
setIsTwoFactorLoading(true); setIsTwoFactorLoading(true);
try { try {
const { data, error } = await authClient.twoFactor.verifyTotp({ const { error } = await authClient.twoFactor.verifyTotp({
code: twoFactorCode.replace(/\s/g, ""), code: twoFactorCode.replace(/\s/g, ""),
}); });
@@ -129,7 +122,7 @@ export default function Home({ IS_CLOUD }: Props) {
toast.success("Logged in successfully"); toast.success("Logged in successfully");
router.push("/dashboard/projects"); router.push("/dashboard/projects");
} catch (error) { } catch (_error) {
toast.error("An error occurred while verifying 2FA code"); toast.error("An error occurred while verifying 2FA code");
} finally { } finally {
setIsTwoFactorLoading(false); setIsTwoFactorLoading(false);
@@ -145,7 +138,7 @@ export default function Home({ IS_CLOUD }: Props) {
setIsBackupCodeLoading(true); setIsBackupCodeLoading(true);
try { try {
const { data, error } = await authClient.twoFactor.verifyBackupCode({ const { error } = await authClient.twoFactor.verifyBackupCode({
code: backupCode.trim(), code: backupCode.trim(),
}); });
@@ -159,7 +152,7 @@ export default function Home({ IS_CLOUD }: Props) {
toast.success("Logged in successfully"); toast.success("Logged in successfully");
router.push("/dashboard/projects"); router.push("/dashboard/projects");
} catch (error) { } catch (_error) {
toast.error("An error occurred while verifying backup code"); toast.error("An error occurred while verifying backup code");
} finally { } finally {
setIsBackupCodeLoading(false); setIsBackupCodeLoading(false);
@@ -396,7 +389,7 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
}, },
}; };
} }
} catch (error) {} } catch (_error) {}
return { return {
props: { props: {

View File

@@ -16,7 +16,6 @@ import { authClient } from "@/lib/auth-client";
import { api } from "@/utils/api"; import { api } from "@/utils/api";
import { IS_CLOUD, getUserByToken } from "@dokploy/server"; import { IS_CLOUD, getUserByToken } from "@dokploy/server";
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
import { AlertTriangle } from "lucide-react";
import type { GetServerSidePropsContext } from "next"; import type { GetServerSidePropsContext } from "next";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
@@ -90,9 +89,6 @@ const Invitation = ({
}, },
); );
const { mutateAsync, error, isError, isSuccess } =
api.auth.createUser.useMutation();
const form = useForm<Register>({ const form = useForm<Register>({
defaultValues: { defaultValues: {
name: "", name: "",
@@ -115,7 +111,7 @@ const Invitation = ({
const onSubmit = async (values: Register) => { const onSubmit = async (values: Register) => {
try { try {
const { data, error } = await authClient.signUp.email({ const { error } = await authClient.signUp.email({
email: values.email, email: values.email,
password: values.password, password: values.password,
name: values.name, name: values.name,
@@ -131,13 +127,13 @@ const Invitation = ({
return; return;
} }
const result = await authClient.organization.acceptInvitation({ const _result = await authClient.organization.acceptInvitation({
invitationId: token, invitationId: token,
}); });
toast.success("Account created successfully"); toast.success("Account created successfully");
router.push("/dashboard/projects"); router.push("/dashboard/projects");
} catch (error) { } catch (_error) {
toast.error("An error occurred while creating your account"); toast.error("An error occurred while creating your account");
} }
}; };
@@ -180,14 +176,14 @@ const Invitation = ({
<div className="w-full"> <div className="w-full">
<div className="p-3" /> <div className="p-3" />
{isError && ( {/* {isError && (
<div className="mx-5 my-2 flex flex-row items-center gap-2 rounded-lg bg-red-50 p-2 dark:bg-red-950"> <div className="mx-5 my-2 flex flex-row items-center gap-2 rounded-lg bg-red-50 p-2 dark:bg-red-950">
<AlertTriangle className="text-red-600 dark:text-red-400" /> <AlertTriangle className="text-red-600 dark:text-red-400" />
<span className="text-sm text-red-600 dark:text-red-400"> <span className="text-sm text-red-600 dark:text-red-400">
{error?.message} {error?.message}
</span> </span>
</div> </div>
)} )} */}
<CardContent className="p-0"> <CardContent className="p-0">
<Form {...form}> <Form {...form}>
@@ -313,7 +309,6 @@ export async function getServerSideProps(ctx: GetServerSidePropsContext) {
const { query } = ctx; const { query } = ctx;
const token = query.token; const token = query.token;
console.log("query", query);
if (typeof token !== "string") { if (typeof token !== "string") {
return { return {

View File

@@ -13,15 +13,15 @@ import {
} from "@/components/ui/form"; } from "@/components/ui/form";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { authClient } from "@/lib/auth-client"; import { authClient } from "@/lib/auth-client";
import { api } from "@/utils/api";
import { IS_CLOUD, isAdminPresent, validateRequest } from "@dokploy/server"; import { IS_CLOUD, isAdminPresent, validateRequest } from "@dokploy/server";
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
import { AlertTriangle } from "lucide-react"; import { AlertTriangle } from "lucide-react";
import type { GetServerSidePropsContext } from "next"; import type { GetServerSidePropsContext } from "next";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { type ReactElement, useEffect } from "react"; import { type ReactElement, useEffect, useState } from "react";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import { toast } from "sonner";
import { z } from "zod"; import { z } from "zod";
const registerSchema = z const registerSchema = z
@@ -72,15 +72,16 @@ interface Props {
const Register = ({ isCloud }: Props) => { const Register = ({ isCloud }: Props) => {
const router = useRouter(); const router = useRouter();
const { mutateAsync, error, isError, data } = const [isError, setIsError] = useState(false);
api.auth.createAdmin.useMutation(); const [error, setError] = useState<string | null>(null);
const [data, setData] = useState<any>(null);
const form = useForm<Register>({ const form = useForm<Register>({
defaultValues: { defaultValues: {
name: "Mauricio Siu", name: "Mauricio Siu",
email: "user5@yopmail.com", email: "user5@yopmail.com",
password: "Password1234", password: "Password123",
confirmPassword: "Password1234", confirmPassword: "Password123",
}, },
resolver: zodResolver(registerSchema), resolver: zodResolver(registerSchema),
}); });
@@ -96,27 +97,19 @@ const Register = ({ isCloud }: Props) => {
name: values.name, name: values.name,
}); });
// const { data, error } = await authClient.admin.createUser({ if (error) {
// name: values.name, setIsError(true);
// email: values.email, setError(error.message || "An error occurred");
// password: values.password, } else {
// role: "superAdmin", toast.success("User registered successfuly", {
// }); duration: 2000,
});
// consol/e.log(data, error); if (!isCloud) {
// await mutateAsync({ router.push("/");
// email: values.email.toLowerCase(), } else {
// password: values.password, setData(data);
// }) }
// .then(() => { }
// toast.success("User registered successfuly", {
// duration: 2000,
// });
// if (!isCloud) {
// router.push("/");
// }
// })
// .catch((e) => e);
}; };
return ( return (
<div className=""> <div className="">
@@ -138,15 +131,15 @@ const Register = ({ isCloud }: Props) => {
</CardDescription> </CardDescription>
<div className="mx-auto w-full max-w-lg bg-transparent"> <div className="mx-auto w-full max-w-lg bg-transparent">
{isError && ( {isError && (
<div className="mx-5 my-2 flex flex-row items-center gap-2 rounded-lg bg-red-50 p-2 dark:bg-red-950"> <div className=" my-2 flex flex-row items-center gap-2 rounded-lg bg-red-50 p-2 dark:bg-red-950">
<AlertTriangle className="text-red-600 dark:text-red-400" /> <AlertTriangle className="text-red-600 dark:text-red-400" />
<span className="text-sm text-red-600 dark:text-red-400"> <span className="text-sm text-red-600 dark:text-red-400">
{error?.message} {error}
</span> </span>
</div> </div>
)} )}
{data?.type === "cloud" && ( {isCloud && data && (
<AlertBlock type="success" className="mx-4 my-2"> <AlertBlock type="success" className="my-2">
<span> <span>
Registered successfully, please check your inbox or spam Registered successfully, please check your inbox or spam
folder to confirm your account. folder to confirm your account.

View File

@@ -77,7 +77,7 @@ export default function Home({ token }: Props) {
resetPasswordToken: token, resetPasswordToken: token,
password: values.password, password: values.password,
}) })
.then((data) => { .then((_data) => {
toast.success("Password reset successfully", { toast.success("Password reset successfully", {
duration: 2000, duration: 2000,
}); });

View File

@@ -43,13 +43,13 @@ type AuthResponse = {
}; };
export default function Home() { export default function Home() {
const [temp, setTemp] = useState<AuthResponse>({ const [temp, _setTemp] = useState<AuthResponse>({
is2FAEnabled: false, is2FAEnabled: false,
authId: "", authId: "",
}); });
const { mutateAsync, isLoading, isError, error } = const { mutateAsync, isLoading, isError, error } =
api.auth.sendResetPasswordEmail.useMutation(); api.auth.sendResetPasswordEmail.useMutation();
const router = useRouter(); const _router = useRouter();
const form = useForm<Login>({ const form = useForm<Login>({
defaultValues: { defaultValues: {
email: "", email: "",
@@ -65,7 +65,7 @@ export default function Home() {
await mutateAsync({ await mutateAsync({
email: values.email, email: values.email,
}) })
.then((data) => { .then((_data) => {
toast.success("Email sent", { toast.success("Email sent", {
duration: 2000, duration: 2000,
}); });
@@ -150,7 +150,7 @@ export default function Home() {
Home.getLayout = (page: ReactElement) => { Home.getLayout = (page: ReactElement) => {
return <OnboardingLayout>{page}</OnboardingLayout>; return <OnboardingLayout>{page}</OnboardingLayout>;
}; };
export async function getServerSideProps(context: GetServerSidePropsContext) { export async function getServerSideProps(_context: GetServerSidePropsContext) {
if (!IS_CLOUD) { if (!IS_CLOUD) {
return { return {
redirect: { redirect: {

View File

@@ -33,7 +33,7 @@ import {
} from "../trpc"; } from "../trpc";
export const authRouter = createTRPCRouter({ export const authRouter = createTRPCRouter({
createAdmin: publicProcedure.mutation(async ({ ctx, input }) => { createAdmin: publicProcedure.mutation(async ({ input }) => {
try { try {
if (!IS_CLOUD) { if (!IS_CLOUD) {
const admin = await db.query.admins.findFirst({}); const admin = await db.query.admins.findFirst({});
@@ -72,9 +72,9 @@ export const authRouter = createTRPCRouter({
}); });
} }
}), }),
createUser: publicProcedure.mutation(async ({ ctx, input }) => { createUser: publicProcedure.mutation(async ({ input }) => {
try { try {
const token = await getUserByToken(input.token); const _token = await getUserByToken(input.token);
// if (token.isExpired) { // if (token.isExpired) {
// throw new TRPCError({ // throw new TRPCError({
// code: "BAD_REQUEST", // code: "BAD_REQUEST",
@@ -103,7 +103,7 @@ export const authRouter = createTRPCRouter({
} }
}), }),
login: publicProcedure.mutation(async ({ ctx, input }) => { login: publicProcedure.mutation(async ({ input }) => {
try { try {
const auth = await findAuthByEmail(input.email); const auth = await findAuthByEmail(input.email);
@@ -169,7 +169,7 @@ export const authRouter = createTRPCRouter({
}), }),
logout: protectedProcedure.mutation(async ({ ctx }) => { logout: protectedProcedure.mutation(async ({ ctx }) => {
const { req, res } = ctx; const { req } = ctx;
const { session } = await validateRequest(req); const { session } = await validateRequest(req);
if (!session) return false; if (!session) return false;
@@ -229,7 +229,7 @@ export const authRouter = createTRPCRouter({
message: "Password is incorrect", message: "Password is incorrect",
}); });
} }
const { req, res } = ctx; const { req } = ctx;
const { session } = await validateRequest(req); const { session } = await validateRequest(req);
if (!session) return false; if (!session) return false;
@@ -245,7 +245,7 @@ export const authRouter = createTRPCRouter({
return true; return true;
}), }),
generateToken: protectedProcedure.mutation(async ({ ctx, input }) => { generateToken: protectedProcedure.mutation(async ({ ctx }) => {
const auth = await findUserById(ctx.user.id); const auth = await findUserById(ctx.user.id);
console.log(auth); console.log(auth);
@@ -276,7 +276,7 @@ export const authRouter = createTRPCRouter({
email: z.string().min(1).email(), email: z.string().min(1).email(),
}), }),
) )
.mutation(async ({ ctx, input }) => { .mutation(async ({ input }) => {
if (!IS_CLOUD) { if (!IS_CLOUD) {
throw new TRPCError({ throw new TRPCError({
code: "NOT_FOUND", code: "NOT_FOUND",
@@ -329,7 +329,7 @@ export const authRouter = createTRPCRouter({
password: z.string().min(1), password: z.string().min(1),
}), }),
) )
.mutation(async ({ ctx, input }) => { .mutation(async ({ input }) => {
if (!IS_CLOUD) { if (!IS_CLOUD) {
throw new TRPCError({ throw new TRPCError({
code: "NOT_FOUND", code: "NOT_FOUND",
@@ -373,7 +373,7 @@ export const authRouter = createTRPCRouter({
confirmationToken: z.string().min(1), confirmationToken: z.string().min(1),
}), }),
) )
.mutation(async ({ ctx, input }) => { .mutation(async ({ input }) => {
if (!IS_CLOUD) { if (!IS_CLOUD) {
throw new TRPCError({ throw new TRPCError({
code: "NOT_FOUND", code: "NOT_FOUND",

View File

@@ -12,6 +12,7 @@ import {
mariadb, mariadb,
mongo, mongo,
mysql, mysql,
organization,
postgres, postgres,
redis, redis,
server, server,
@@ -102,6 +103,18 @@ export const serverRouter = createTRPCRouter({
return result; return result;
}), }),
count: protectedProcedure.query(async ({ ctx }) => {
const organizations = await db.query.organization.findMany({
where: eq(organization.ownerId, ctx.user.id),
with: {
servers: true,
},
});
const servers = organizations.flatMap((org) => org.servers);
return servers.length ?? 0;
}),
withSSHKey: protectedProcedure.query(async ({ ctx }) => { withSSHKey: protectedProcedure.query(async ({ ctx }) => {
const result = await db.query.server.findMany({ const result = await db.query.server.findMany({
orderBy: desc(server.createdAt), orderBy: desc(server.createdAt),

View File

@@ -56,7 +56,7 @@ export const stripeRouter = createTRPCRouter({
}); });
const items = getStripeItems(input.serverQuantity, input.isAnnual); const items = getStripeItems(input.serverQuantity, input.isAnnual);
const user = await findUserById(ctx.user.ownerId); const user = await findUserById(ctx.user.id);
let stripeCustomerId = user.stripeCustomerId; let stripeCustomerId = user.stripeCustomerId;
@@ -78,7 +78,7 @@ export const stripeRouter = createTRPCRouter({
customer: stripeCustomerId, customer: stripeCustomerId,
}), }),
metadata: { metadata: {
ownerId: user.id, adminId: user.id,
}, },
allow_promotion_codes: true, allow_promotion_codes: true,
success_url: `${WEBSITE_URL}/dashboard/settings/servers?success=true`, success_url: `${WEBSITE_URL}/dashboard/settings/servers?success=true`,
@@ -88,7 +88,7 @@ export const stripeRouter = createTRPCRouter({
return { sessionId: session.id }; return { sessionId: session.id };
}), }),
createCustomerPortalSession: adminProcedure.mutation(async ({ ctx }) => { createCustomerPortalSession: adminProcedure.mutation(async ({ ctx }) => {
const user = await findUserById(ctx.user.ownerId); const user = await findUserById(ctx.user.id);
if (!user.stripeCustomerId) { if (!user.stripeCustomerId) {
throw new TRPCError({ throw new TRPCError({

View File

@@ -1,15 +1,10 @@
import bc from "bcrypt";
import { drizzle } from "drizzle-orm/postgres-js"; import { drizzle } from "drizzle-orm/postgres-js";
import postgres from "postgres"; import postgres from "postgres";
const connectionString = process.env.DATABASE_URL!; const connectionString = process.env.DATABASE_URL!;
const pg = postgres(connectionString, { max: 1 }); const pg = postgres(connectionString, { max: 1 });
const db = drizzle(pg); const _db = drizzle(pg);
function password(txt: string) {
return bc.hashSync(txt, 10);
}
async function seed() { async function seed() {
console.log("> Seed:", process.env.DATABASE_PATH, "\n"); console.log("> Seed:", process.env.DATABASE_PATH, "\n");

View File

@@ -6,7 +6,7 @@ export const isWSL = async () => {
const { stdout } = await execAsync("uname -r"); const { stdout } = await execAsync("uname -r");
const isWSL = stdout.includes("microsoft"); const isWSL = stdout.includes("microsoft");
return isWSL; return isWSL;
} catch (error) { } catch (_error) {
return false; return false;
} }
}; };

View File

@@ -50,8 +50,8 @@ export const setupDockerContainerTerminalWebSocketServer = (
throw new Error("No SSH key available for this server"); throw new Error("No SSH key available for this server");
const conn = new Client(); const conn = new Client();
let stdout = ""; let _stdout = "";
let stderr = ""; let _stderr = "";
conn conn
.once("ready", () => { .once("ready", () => {
conn.exec( conn.exec(
@@ -61,16 +61,16 @@ export const setupDockerContainerTerminalWebSocketServer = (
if (err) throw err; if (err) throw err;
stream stream
.on("close", (code: number, signal: string) => { .on("close", (code: number, _signal: string) => {
ws.send(`\nContainer closed with code: ${code}\n`); ws.send(`\nContainer closed with code: ${code}\n`);
conn.end(); conn.end();
}) })
.on("data", (data: string) => { .on("data", (data: string) => {
stdout += data.toString(); _stdout += data.toString();
ws.send(data.toString()); ws.send(data.toString());
}) })
.stderr.on("data", (data) => { .stderr.on("data", (data) => {
stderr += data.toString(); _stderr += data.toString();
ws.send(data.toString()); ws.send(data.toString());
console.error("Error: ", data.toString()); console.error("Error: ", data.toString());
}); });

View File

@@ -32,7 +32,7 @@ export const setupDrawerLogsWebSocketServer = (
}); });
wssTerm.on("connection", async (ws, req) => { wssTerm.on("connection", async (ws, req) => {
const url = new URL(req.url || "", `http://${req.headers.host}`); const _url = new URL(req.url || "", `http://${req.headers.host}`);
const { user, session } = await validateRequest(req); const { user, session } = await validateRequest(req);
if (!user || !session) { if (!user || !session) {

View File

@@ -103,7 +103,7 @@ export const setupDeploymentLogsWebSocketServer = (
ws.close(); ws.close();
}); });
} }
} catch (error) { } catch (_error) {
// @ts-ignore // @ts-ignore
// const errorMessage = error?.message as unknown as string; // const errorMessage = error?.message as unknown as string;
// ws.send(errorMessage); // ws.send(errorMessage);

View File

@@ -144,8 +144,8 @@ export const setupTerminalWebSocketServer = (
} }
const conn = new Client(); const conn = new Client();
let stdout = ""; let _stdout = "";
let stderr = ""; let _stderr = "";
ws.send("Connecting...\n"); ws.send("Connecting...\n");
@@ -158,16 +158,16 @@ export const setupTerminalWebSocketServer = (
if (err) throw err; if (err) throw err;
stream stream
.on("close", (code: number, signal: string) => { .on("close", (code: number, _signal: string) => {
ws.send(`\nContainer closed with code: ${code}\n`); ws.send(`\nContainer closed with code: ${code}\n`);
conn.end(); conn.end();
}) })
.on("data", (data: string) => { .on("data", (data: string) => {
stdout += data.toString(); _stdout += data.toString();
ws.send(data.toString()); ws.send(data.toString());
}) })
.stderr.on("data", (data) => { .stderr.on("data", (data) => {
stderr += data.toString(); _stderr += data.toString();
ws.send(data.toString()); ws.send(data.toString());
console.error("Error: ", data.toString()); console.error("Error: ", data.toString());
}); });

View File

@@ -7,7 +7,7 @@ import {
} from "../utils"; } from "../utils";
export function generate(schema: Schema): Template { export function generate(schema: Schema): Template {
const mainServiceHash = generateHash(schema.projectName); const _mainServiceHash = generateHash(schema.projectName);
const domains: DomainSchema[] = [ const domains: DomainSchema[] = [
{ {

View File

@@ -7,7 +7,7 @@ import {
} from "../utils"; } from "../utils";
export function generate(schema: Schema): Template { export function generate(schema: Schema): Template {
const mainServiceHash = generateHash(schema.projectName); const _mainServiceHash = generateHash(schema.projectName);
const mainDomain = generateRandomDomain(schema); const mainDomain = generateRandomDomain(schema);
const domains: DomainSchema[] = [ const domains: DomainSchema[] = [

View File

@@ -1,6 +1,6 @@
import type { Schema, Template } from "../utils"; import type { Schema, Template } from "../utils";
export function generate(schema: Schema): Template { export function generate(_schema: Schema): Template {
const envs = [`CLOUDFLARE_TUNNEL_TOKEN="<INSERT TOKEN>"`]; const envs = [`CLOUDFLARE_TUNNEL_TOKEN="<INSERT TOKEN>"`];
return { return {

View File

@@ -8,7 +8,7 @@ import {
export function generate(schema: Schema): Template { export function generate(schema: Schema): Template {
const mainDomain = generateRandomDomain(schema); const mainDomain = generateRandomDomain(schema);
const secretKeyBase = generateBase64(64); const _secretKeyBase = generateBase64(64);
const domains: DomainSchema[] = [ const domains: DomainSchema[] = [
{ {

View File

@@ -11,7 +11,7 @@ export function generate(schema: Schema): Template {
const mainDomain = generateRandomDomain(schema); const mainDomain = generateRandomDomain(schema);
const dbPassword = generatePassword(); const dbPassword = generatePassword();
const dbUser = "immich"; const dbUser = "immich";
const appSecret = generateBase64(32); const _appSecret = generateBase64(32);
const domains: DomainSchema[] = [ const domains: DomainSchema[] = [
{ {

View File

@@ -1,6 +1,6 @@
import type { Schema, Template } from "../utils"; import type { Schema, Template } from "../utils";
export function generate(schema: Schema): Template { export function generate(_schema: Schema): Template {
const mounts: Template["mounts"] = [ const mounts: Template["mounts"] = [
{ {
filePath: "init-mongo.sh", filePath: "init-mongo.sh",

View File

@@ -28,19 +28,16 @@ export const certificates = pgTable("certificate", {
}), }),
}); });
export const certificatesRelations = relations( export const certificatesRelations = relations(certificates, ({ one }) => ({
certificates, server: one(server, {
({ one, many }) => ({ fields: [certificates.serverId],
server: one(server, { references: [server.serverId],
fields: [certificates.serverId],
references: [server.serverId],
}),
organization: one(organization, {
fields: [certificates.organizationId],
references: [organization.id],
}),
}), }),
); organization: one(organization, {
fields: [certificates.organizationId],
references: [organization.id],
}),
}));
export const apiCreateCertificate = createInsertSchema(certificates, { export const apiCreateCertificate = createInsertSchema(certificates, {
name: z.string().min(1), name: z.string().min(1),

View File

@@ -29,7 +29,7 @@ export const gitProvider = pgTable("git_provider", {
.references(() => organization.id, { onDelete: "cascade" }), .references(() => organization.id, { onDelete: "cascade" }),
}); });
export const gitProviderRelations = relations(gitProvider, ({ one, many }) => ({ export const gitProviderRelations = relations(gitProvider, ({ one }) => ({
github: one(github, { github: one(github, {
fields: [gitProvider.gitProviderId], fields: [gitProvider.gitProviderId],
references: [github.gitProviderId], references: [github.gitProviderId],

View File

@@ -32,7 +32,7 @@ export const registry = pgTable("registry", {
.references(() => organization.id, { onDelete: "cascade" }), .references(() => organization.id, { onDelete: "cascade" }),
}); });
export const registryRelations = relations(registry, ({ one, many }) => ({ export const registryRelations = relations(registry, ({ many }) => ({
applications: many(applications), applications: many(applications),
})); }));

View File

@@ -2,14 +2,12 @@ import type { IncomingMessage } from "node:http";
import * as bcrypt from "bcrypt"; import * as bcrypt from "bcrypt";
import { betterAuth } from "better-auth"; import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle"; import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { import { organization, twoFactor } from "better-auth/plugins";
createAuthMiddleware,
organization,
twoFactor,
} from "better-auth/plugins";
import { and, desc, eq } from "drizzle-orm"; import { and, desc, eq } from "drizzle-orm";
import { db } from "../db"; import { db } from "../db";
import * as schema from "../db/schema"; import * as schema from "../db/schema";
import { sendVerificationEmail } from "../verification/send-verification-email";
import { IS_CLOUD } from "../constants";
export const auth = betterAuth({ export const auth = betterAuth({
database: drizzleAdapter(db, { database: drizzleAdapter(db, {
@@ -27,9 +25,18 @@ export const auth = betterAuth({
clientSecret: process.env.GOOGLE_CLIENT_SECRET as string, clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
}, },
}, },
emailVerification: {
sendOnSignUp: true,
autoSignInAfterVerification: true,
sendVerificationEmail: async ({ user, url }) => {
console.log("Sending verification email to", user.email);
await sendVerificationEmail(user.email, url);
},
},
emailAndPassword: { emailAndPassword: {
enabled: true, enabled: true,
autoSignIn: !IS_CLOUD,
requireEmailVerification: IS_CLOUD,
password: { password: {
async hash(password) { async hash(password) {
return bcrypt.hashSync(password, 10); return bcrypt.hashSync(password, 10);
@@ -39,33 +46,37 @@ export const auth = betterAuth({
}, },
}, },
}, },
hooks: {
after: createAuthMiddleware(async (ctx) => {
if (ctx.path.startsWith("/sign-up")) {
const newSession = ctx.context.newSession;
if (ctx.headers?.get("x-dokploy-token")) {
} else {
const organization = await db
.insert(schema.organization)
.values({
name: "My Organization",
ownerId: newSession?.user?.id || "",
createdAt: new Date(),
})
.returning()
.then((res) => res[0]);
await db.insert(schema.member).values({
userId: newSession?.user?.id || "",
organizationId: organization?.id || "",
role: "owner",
createdAt: new Date(),
});
}
}
}),
},
databaseHooks: { databaseHooks: {
user: {
create: {
after: async (user) => {
const isAdminPresent = await db.query.member.findFirst({
where: eq(schema.member.role, "owner"),
});
if (IS_CLOUD || !isAdminPresent) {
await db.transaction(async (tx) => {
const organization = await tx
.insert(schema.organization)
.values({
name: "My Organization",
ownerId: user.id,
createdAt: new Date(),
})
.returning()
.then((res) => res[0]);
await tx.insert(schema.member).values({
userId: user.id,
organizationId: organization?.id || "",
role: "owner",
createdAt: new Date(),
});
});
}
},
},
},
session: { session: {
create: { create: {
before: async (session) => { before: async (session) => {
@@ -106,7 +117,7 @@ export const auth = betterAuth({
plugins: [ plugins: [
twoFactor(), twoFactor(),
organization({ organization({
async sendInvitationEmail(data, request) { async sendInvitationEmail(data, _request) {
const inviteLink = `https://example.com/accept-invitation/${data.id}`; const inviteLink = `https://example.com/accept-invitation/${data.id}`;
// https://example.com/accept-invitation/8jlBi9Tb9isDb8mc8Sb85u1BaJYklKB2 // https://example.com/accept-invitation/8jlBi9Tb9isDb8mc8Sb85u1BaJYklKB2
// sendOrganizationInvitation({ // sendOrganizationInvitation({

View File

@@ -1,94 +0,0 @@
// import {
// decodeHex,
// encodeBase32LowerCaseNoPadding,
// encodeHexLowerCase,
// } from "@oslojs/encoding";
// import { generateRandomString } from "@oslojs/crypto/random";
// import { constantTimeEqual } from "@oslojs/crypto/subtle";
// import { scrypt } from "./scrypt/index";
// import type { RandomReader } from "@oslojs/crypto/random";
// async function generateScryptKey(
// data: string,
// salt: string,
// blockSize = 16,
// ): Promise<Uint8Array> {
// const encodedData = new TextEncoder().encode(data);
// const encodedSalt = new TextEncoder().encode(salt);
// const keyUint8Array = await scrypt(encodedData, encodedSalt, {
// N: 16384,
// r: blockSize,
// p: 1,
// dkLen: 64,
// });
// return new Uint8Array(keyUint8Array);
// }
// const random: RandomReader = {
// read(bytes: Uint8Array): void {
// crypto.getRandomValues(bytes);
// },
// };
// export function generateId(length: number): string {
// const alphabet = "abcdefghijklmnopqrstuvwxyz0123456789";
// return generateRandomString(random, alphabet, length);
// }
// export function generateIdFromEntropySize(size: number): string {
// const buffer = crypto.getRandomValues(new Uint8Array(size));
// return encodeBase32LowerCaseNoPadding(buffer);
// }
// export class Scrypt implements PasswordHashingAlgorithm {
// async hash(password: string): Promise<string> {
// const salt = encodeHexLowerCase(crypto.getRandomValues(new Uint8Array(16)));
// const key = await generateScryptKey(password.normalize("NFKC"), salt);
// return `${salt}:${encodeHexLowerCase(key)}`;
// }
// async verify(hash: string, password: string): Promise<boolean> {
// const parts = hash.split(":");
// if (parts.length !== 2) return false;
// const [salt, key] = parts;
// const targetKey = await generateScryptKey(password.normalize("NFKC"), salt);
// return constantTimeEqual(targetKey, decodeHex(key));
// }
// }
// export class LegacyScrypt implements PasswordHashingAlgorithm {
// async hash(password: string): Promise<string> {
// const salt = encodeHexLowerCase(crypto.getRandomValues(new Uint8Array(16)));
// const key = await generateScryptKey(password.normalize("NFKC"), salt);
// return `s2:${salt}:${encodeHexLowerCase(key)}`;
// }
// async verify(hash: string, password: string): Promise<boolean> {
// const parts = hash.split(":");
// if (parts.length === 2) {
// const [salt, key] = parts;
// const targetKey = await generateScryptKey(
// password.normalize("NFKC"),
// salt,
// 8,
// );
// const result = constantTimeEqual(targetKey, decodeHex(key));
// return result;
// }
// if (parts.length !== 3) return false;
// const [version, salt, key] = parts;
// if (version === "s2") {
// const targetKey = await generateScryptKey(
// password.normalize("NFKC"),
// salt,
// );
// return constantTimeEqual(targetKey, decodeHex(key));
// }
// return false;
// }
// }
// export interface PasswordHashingAlgorithm {
// hash(password: string): Promise<string>;
// verify(hash: string, password: string): Promise<boolean>;
// }

View File

@@ -1 +0,0 @@
//

Some files were not shown because too many files have changed in this diff Show More