mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
feat(destinations): add createdAt timestamp and display creation date
This commit is contained in:
@@ -39,12 +39,12 @@ import { S3_PROVIDERS } from "./constants";
|
||||
|
||||
const addDestination = z.object({
|
||||
name: z.string().min(1, "Name is required"),
|
||||
provider: z.string().optional(),
|
||||
accessKeyId: z.string(),
|
||||
secretAccessKey: z.string(),
|
||||
bucket: z.string(),
|
||||
provider: z.string().min(1, "Provider is required"),
|
||||
accessKeyId: z.string().min(1, "Access Key Id is required"),
|
||||
secretAccessKey: z.string().min(1, "Secret Access Key is required"),
|
||||
bucket: z.string().min(1, "Bucket is required"),
|
||||
region: z.string(),
|
||||
endpoint: z.string(),
|
||||
endpoint: z.string().min(1, "Endpoint is required"),
|
||||
serverId: z.string().optional(),
|
||||
});
|
||||
|
||||
@@ -129,6 +129,58 @@ export const HandleDestinations = ({ destinationId }: Props) => {
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
const handleTestConnection = async (serverId?: string) => {
|
||||
const result = await form.trigger([
|
||||
"provider",
|
||||
"accessKeyId",
|
||||
"secretAccessKey",
|
||||
"bucket",
|
||||
"endpoint",
|
||||
]);
|
||||
|
||||
if (!result) {
|
||||
const errors = form.formState.errors;
|
||||
const errorFields = Object.entries(errors)
|
||||
.map(([field, error]) => `${field}: ${error?.message}`)
|
||||
.filter(Boolean)
|
||||
.join("\n");
|
||||
|
||||
toast.error("Please fill all required fields", {
|
||||
description: errorFields,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const provider = form.getValues("provider");
|
||||
const accessKey = form.getValues("accessKeyId");
|
||||
const secretKey = form.getValues("secretAccessKey");
|
||||
const bucket = form.getValues("bucket");
|
||||
const endpoint = form.getValues("endpoint");
|
||||
const region = form.getValues("region");
|
||||
|
||||
const connectionString = `:s3,provider=${provider},access_key_id=${accessKey},secret_access_key=${secretKey},endpoint=${endpoint}${region ? `,region=${region}` : ""}:${bucket}`;
|
||||
|
||||
await testConnection({
|
||||
provider,
|
||||
accessKey,
|
||||
bucket,
|
||||
endpoint,
|
||||
name: "Test",
|
||||
region,
|
||||
secretAccessKey: secretKey,
|
||||
serverId,
|
||||
})
|
||||
.then(() => {
|
||||
toast.success("Connection Success");
|
||||
})
|
||||
.catch((e) => {
|
||||
toast.error("Error connecting to provider", {
|
||||
description: `${e.message}\n\nTry manually: rclone ls ${connectionString}`,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogTrigger className="" asChild>
|
||||
@@ -349,26 +401,9 @@ export const HandleDestinations = ({ destinationId }: Props) => {
|
||||
<Button
|
||||
type="button"
|
||||
variant={"secondary"}
|
||||
isLoading={isLoading}
|
||||
isLoading={isLoadingConnection}
|
||||
onClick={async () => {
|
||||
await testConnection({
|
||||
provider: form.getValues("provider") || "",
|
||||
accessKey: form.getValues("accessKeyId"),
|
||||
bucket: form.getValues("bucket"),
|
||||
endpoint: form.getValues("endpoint"),
|
||||
name: "Test",
|
||||
region: form.getValues("region"),
|
||||
secretAccessKey: form.getValues("secretAccessKey"),
|
||||
serverId: form.getValues("serverId"),
|
||||
})
|
||||
.then(async () => {
|
||||
toast.success("Connection Success");
|
||||
})
|
||||
.catch((e) => {
|
||||
toast.error("Error connecting the provider", {
|
||||
description: e.message,
|
||||
});
|
||||
});
|
||||
await handleTestConnection(form.getValues("serverId"));
|
||||
}}
|
||||
>
|
||||
Test Connection
|
||||
@@ -380,21 +415,7 @@ export const HandleDestinations = ({ destinationId }: Props) => {
|
||||
type="button"
|
||||
variant="secondary"
|
||||
onClick={async () => {
|
||||
await testConnection({
|
||||
provider: form.getValues("provider") || "",
|
||||
accessKey: form.getValues("accessKeyId"),
|
||||
bucket: form.getValues("bucket"),
|
||||
endpoint: form.getValues("endpoint"),
|
||||
name: "Test",
|
||||
region: form.getValues("region"),
|
||||
secretAccessKey: form.getValues("secretAccessKey"),
|
||||
})
|
||||
.then(async () => {
|
||||
toast.success("Connection Success");
|
||||
})
|
||||
.catch(() => {
|
||||
toast.error("Error connecting the provider");
|
||||
});
|
||||
await handleTestConnection();
|
||||
}}
|
||||
>
|
||||
Test connection
|
||||
|
||||
@@ -56,9 +56,17 @@ export const ShowDestinations = () => {
|
||||
className="flex items-center justify-between bg-sidebar p-1 w-full rounded-lg"
|
||||
>
|
||||
<div className="flex items-center justify-between p-3.5 rounded-lg bg-background border w-full">
|
||||
<span className="text-sm">
|
||||
{index + 1}. {destination.name}
|
||||
</span>
|
||||
<div className="flex flex-col gap-1">
|
||||
<span className="text-sm">
|
||||
{index + 1}. {destination.name}
|
||||
</span>
|
||||
<span className="text-xs text-muted-foreground">
|
||||
Created at:{" "}
|
||||
{new Date(
|
||||
destination.createdAt,
|
||||
).toLocaleDateString()}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex flex-row gap-1">
|
||||
<HandleDestinations
|
||||
destinationId={destination.destinationId}
|
||||
|
||||
1
apps/dokploy/drizzle/0070_useful_serpent_society.sql
Normal file
1
apps/dokploy/drizzle/0070_useful_serpent_society.sql
Normal file
@@ -0,0 +1 @@
|
||||
ALTER TABLE "destination" ADD COLUMN "createdAt" timestamp DEFAULT now() NOT NULL;
|
||||
5126
apps/dokploy/drizzle/meta/0070_snapshot.json
Normal file
5126
apps/dokploy/drizzle/meta/0070_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -491,6 +491,13 @@
|
||||
"when": 1741152916611,
|
||||
"tag": "0069_legal_bill_hollister",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 70,
|
||||
"version": "7",
|
||||
"when": 1741322697251,
|
||||
"tag": "0070_useful_serpent_society",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
updateDestinationById,
|
||||
} from "@dokploy/server";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { eq, desc } from "drizzle-orm";
|
||||
|
||||
export const destinationRouter = createTRPCRouter({
|
||||
create: adminProcedure
|
||||
@@ -98,6 +98,7 @@ export const destinationRouter = createTRPCRouter({
|
||||
all: protectedProcedure.query(async ({ ctx }) => {
|
||||
return await db.query.destinations.findMany({
|
||||
where: eq(destinations.organizationId, ctx.session.activeOrganizationId),
|
||||
orderBy: [desc(destinations.createdAt)],
|
||||
});
|
||||
}),
|
||||
remove: adminProcedure
|
||||
|
||||
Reference in New Issue
Block a user