mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
refactor(multi-server): add modals and separate server actions
This commit is contained in:
@@ -17,7 +17,7 @@ import {
|
||||
import { adminProcedure, createTRPCRouter, publicProcedure } from "../trpc";
|
||||
|
||||
export const adminRouter = createTRPCRouter({
|
||||
one: adminProcedure.query(async () => {
|
||||
one: adminProcedure.query(async ({ ctx }) => {
|
||||
const { sshPrivateKey, ...rest } = await findAdmin();
|
||||
return {
|
||||
haveSSH: !!sshPrivateKey,
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
apiReadStatsLogs,
|
||||
apiReadTraefikConfig,
|
||||
apiSaveSSHKey,
|
||||
apiStorage,
|
||||
apiServerSchema,
|
||||
apiTraefikConfig,
|
||||
apiUpdateDockerCleanup,
|
||||
} from "@/server/db/schema";
|
||||
@@ -57,6 +57,7 @@ import {
|
||||
} from "../services/settings";
|
||||
import { canAccessToTraefikFiles } from "../services/user";
|
||||
import { adminProcedure, createTRPCRouter, protectedProcedure } from "../trpc";
|
||||
import { findServerById, updateServerById } from "../services/server";
|
||||
|
||||
export const settingsRouter = createTRPCRouter({
|
||||
reloadServer: adminProcedure.mutation(async () => {
|
||||
@@ -67,7 +68,7 @@ export const settingsRouter = createTRPCRouter({
|
||||
return true;
|
||||
}),
|
||||
reloadTraefik: adminProcedure
|
||||
.input(apiStorage)
|
||||
.input(apiServerSchema)
|
||||
.mutation(async ({ input }) => {
|
||||
try {
|
||||
if (input?.serverId) {
|
||||
@@ -94,44 +95,46 @@ export const settingsRouter = createTRPCRouter({
|
||||
}),
|
||||
|
||||
cleanUnusedImages: adminProcedure
|
||||
.input(apiStorage)
|
||||
.input(apiServerSchema)
|
||||
.mutation(async ({ input }) => {
|
||||
await cleanUpUnusedImages(input?.serverId);
|
||||
return true;
|
||||
}),
|
||||
cleanUnusedVolumes: adminProcedure
|
||||
.input(apiStorage)
|
||||
.input(apiServerSchema)
|
||||
.mutation(async ({ input }) => {
|
||||
await cleanUpUnusedVolumes(input?.serverId);
|
||||
return true;
|
||||
}),
|
||||
cleanStoppedContainers: adminProcedure
|
||||
.input(apiStorage)
|
||||
.input(apiServerSchema)
|
||||
.mutation(async ({ input }) => {
|
||||
await cleanStoppedContainers(input?.serverId);
|
||||
return true;
|
||||
}),
|
||||
cleanDockerBuilder: adminProcedure
|
||||
.input(apiStorage)
|
||||
.input(apiServerSchema)
|
||||
.mutation(async ({ input }) => {
|
||||
await cleanUpDockerBuilder(input?.serverId);
|
||||
}),
|
||||
cleanDockerPrune: adminProcedure
|
||||
.input(apiStorage)
|
||||
.input(apiServerSchema)
|
||||
.mutation(async ({ input }) => {
|
||||
await cleanUpSystemPrune(input?.serverId);
|
||||
await cleanUpDockerBuilder(input?.serverId);
|
||||
|
||||
return true;
|
||||
}),
|
||||
cleanAll: adminProcedure.input(apiStorage).mutation(async ({ input }) => {
|
||||
await cleanUpUnusedImages(input?.serverId);
|
||||
await cleanStoppedContainers(input?.serverId);
|
||||
await cleanUpDockerBuilder(input?.serverId);
|
||||
await cleanUpSystemPrune(input?.serverId);
|
||||
cleanAll: adminProcedure
|
||||
.input(apiServerSchema)
|
||||
.mutation(async ({ input }) => {
|
||||
await cleanUpUnusedImages(input?.serverId);
|
||||
await cleanStoppedContainers(input?.serverId);
|
||||
await cleanUpDockerBuilder(input?.serverId);
|
||||
await cleanUpSystemPrune(input?.serverId);
|
||||
|
||||
return true;
|
||||
}),
|
||||
return true;
|
||||
}),
|
||||
cleanMonitoring: adminProcedure.mutation(async () => {
|
||||
const { MONITORING_PATH } = paths();
|
||||
await recreateDirectory(MONITORING_PATH);
|
||||
@@ -175,25 +178,43 @@ export const settingsRouter = createTRPCRouter({
|
||||
updateDockerCleanup: adminProcedure
|
||||
.input(apiUpdateDockerCleanup)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
await updateAdmin(ctx.user.authId, {
|
||||
enableDockerCleanup: input.enableDockerCleanup,
|
||||
});
|
||||
|
||||
const admin = await findAdmin();
|
||||
|
||||
if (admin.enableDockerCleanup) {
|
||||
scheduleJob("docker-cleanup", "0 0 * * *", async () => {
|
||||
console.log(
|
||||
`Docker Cleanup ${new Date().toLocaleString()}] Running...`,
|
||||
);
|
||||
await cleanUpUnusedImages();
|
||||
await cleanUpDockerBuilder();
|
||||
await cleanUpSystemPrune();
|
||||
await sendDockerCleanupNotifications();
|
||||
if (input.serverId) {
|
||||
await updateServerById(input.serverId, {
|
||||
enableDockerCleanup: input.enableDockerCleanup,
|
||||
});
|
||||
|
||||
const server = await findServerById(input.serverId);
|
||||
if (server.enableDockerCleanup) {
|
||||
scheduleJob("docker-cleanup", "0 0 * * *", async () => {
|
||||
console.log(
|
||||
`Docker Cleanup ${new Date().toLocaleString()}] Running...`,
|
||||
);
|
||||
await cleanUpUnusedImages(server.serverId);
|
||||
await cleanUpDockerBuilder(server.serverId);
|
||||
await cleanUpSystemPrune(server.serverId);
|
||||
await sendDockerCleanupNotifications();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
const currentJob = scheduledJobs["docker-cleanup"];
|
||||
currentJob?.cancel();
|
||||
await updateAdmin(ctx.user.authId, {
|
||||
enableDockerCleanup: input.enableDockerCleanup,
|
||||
});
|
||||
const admin = await findAdmin();
|
||||
|
||||
if (admin.enableDockerCleanup) {
|
||||
scheduleJob("docker-cleanup", "0 0 * * *", async () => {
|
||||
console.log(
|
||||
`Docker Cleanup ${new Date().toLocaleString()}] Running...`,
|
||||
);
|
||||
await cleanUpUnusedImages();
|
||||
await cleanUpDockerBuilder();
|
||||
await cleanUpSystemPrune();
|
||||
await sendDockerCleanupNotifications();
|
||||
});
|
||||
} else {
|
||||
const currentJob = scheduledJobs["docker-cleanup"];
|
||||
currentJob?.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -253,7 +274,7 @@ export const settingsRouter = createTRPCRouter({
|
||||
return getDokployVersion();
|
||||
}),
|
||||
readDirectories: protectedProcedure
|
||||
.input(apiStorage)
|
||||
.input(apiServerSchema)
|
||||
.query(async ({ ctx, input }) => {
|
||||
if (ctx.user.rol === "user") {
|
||||
const canAccess = await canAccessToTraefikFiles(ctx.user.authId);
|
||||
@@ -352,17 +373,19 @@ export const settingsRouter = createTRPCRouter({
|
||||
return openApiDocument;
|
||||
},
|
||||
),
|
||||
readTraefikEnv: adminProcedure.input(apiStorage).query(async ({ input }) => {
|
||||
const command =
|
||||
"docker service inspect --format='{{range .Spec.TaskTemplate.ContainerSpec.Env}}{{println .}}{{end}}' dokploy-traefik";
|
||||
readTraefikEnv: adminProcedure
|
||||
.input(apiServerSchema)
|
||||
.query(async ({ input }) => {
|
||||
const command =
|
||||
"docker service inspect --format='{{range .Spec.TaskTemplate.ContainerSpec.Env}}{{println .}}{{end}}' dokploy-traefik";
|
||||
|
||||
if (input?.serverId) {
|
||||
const result = await execAsyncRemote(input.serverId, command);
|
||||
if (input?.serverId) {
|
||||
const result = await execAsyncRemote(input.serverId, command);
|
||||
return result.stdout.trim();
|
||||
}
|
||||
const result = await execAsync(command);
|
||||
return result.stdout.trim();
|
||||
}
|
||||
const result = await execAsync(command);
|
||||
return result.stdout.trim();
|
||||
}),
|
||||
}),
|
||||
|
||||
writeTraefikEnv: adminProcedure
|
||||
.input(z.object({ env: z.string(), serverId: z.string().optional() }))
|
||||
@@ -376,7 +399,7 @@ export const settingsRouter = createTRPCRouter({
|
||||
return true;
|
||||
}),
|
||||
haveTraefikDashboardPortEnabled: adminProcedure
|
||||
.input(apiStorage)
|
||||
.input(apiServerSchema)
|
||||
.query(async ({ input }) => {
|
||||
const command = `docker service inspect --format='{{json .Endpoint.Ports}}' dokploy-traefik`;
|
||||
|
||||
|
||||
@@ -105,20 +105,44 @@ echo "$json_output"
|
||||
}
|
||||
const items = readdirSync(dirPath, { withFileTypes: true });
|
||||
|
||||
return items.map((item) => {
|
||||
const fullPath = join(dirPath, item.name);
|
||||
if (item.isDirectory()) {
|
||||
return {
|
||||
id: fullPath,
|
||||
name: item.name,
|
||||
type: "directory",
|
||||
children: readDirectory(fullPath),
|
||||
};
|
||||
const stack = [dirPath];
|
||||
const result: TreeDataItem[] = [];
|
||||
const parentMap: Record<string, TreeDataItem[]> = {};
|
||||
|
||||
while (stack.length > 0) {
|
||||
const currentPath = stack.pop();
|
||||
if (!currentPath) continue;
|
||||
|
||||
const items = readdirSync(currentPath, { withFileTypes: true });
|
||||
const currentDirectoryResult: TreeDataItem[] = [];
|
||||
|
||||
for (const item of items) {
|
||||
const fullPath = join(currentPath, item.name);
|
||||
if (item.isDirectory()) {
|
||||
stack.push(fullPath);
|
||||
const directoryItem: TreeDataItem = {
|
||||
id: fullPath,
|
||||
name: item.name,
|
||||
type: "directory",
|
||||
children: [],
|
||||
};
|
||||
currentDirectoryResult.push(directoryItem);
|
||||
parentMap[fullPath] = directoryItem.children as TreeDataItem[];
|
||||
} else {
|
||||
const fileItem: TreeDataItem = {
|
||||
id: fullPath,
|
||||
name: item.name,
|
||||
type: "file",
|
||||
};
|
||||
currentDirectoryResult.push(fileItem);
|
||||
}
|
||||
}
|
||||
return {
|
||||
id: fullPath,
|
||||
name: item.name,
|
||||
type: "file",
|
||||
};
|
||||
}) as unknown as Promise<TreeDataItem[]>;
|
||||
|
||||
if (parentMap[currentPath]) {
|
||||
parentMap[currentPath].push(...currentDirectoryResult);
|
||||
} else {
|
||||
result.push(...currentDirectoryResult);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
@@ -63,7 +63,10 @@ export const apiUpdateDockerCleanup = createSchema
|
||||
.pick({
|
||||
enableDockerCleanup: true,
|
||||
})
|
||||
.required();
|
||||
.required()
|
||||
.extend({
|
||||
serverId: z.string().optional(),
|
||||
});
|
||||
|
||||
export const apiTraefikConfig = z.object({
|
||||
traefikConfig: z.string().min(1),
|
||||
@@ -84,7 +87,7 @@ export const apiEnableDashboard = z.object({
|
||||
serverId: z.string().optional(),
|
||||
});
|
||||
|
||||
export const apiStorage = z
|
||||
export const apiServerSchema = z
|
||||
.object({
|
||||
serverId: z.string().optional(),
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { relations } from "drizzle-orm";
|
||||
import { integer, pgTable, text } from "drizzle-orm/pg-core";
|
||||
import { boolean, integer, pgTable, text } from "drizzle-orm/pg-core";
|
||||
import { createInsertSchema } from "drizzle-zod";
|
||||
import { nanoid } from "nanoid";
|
||||
import { z } from "zod";
|
||||
@@ -30,7 +30,7 @@ export const server = pgTable("server", {
|
||||
appName: text("appName")
|
||||
.notNull()
|
||||
.$defaultFn(() => generateAppName("server")),
|
||||
redisPassword: text("redisPassword").notNull().default("xYBugfHkULig1iLN"),
|
||||
enableDockerCleanup: boolean("enableDockerCleanup").notNull().default(false),
|
||||
createdAt: text("createdAt")
|
||||
.notNull()
|
||||
.$defaultFn(() => new Date().toISOString()),
|
||||
|
||||
Reference in New Issue
Block a user