feat/fix: fixed stop button & added start button

This commit is contained in:
190km
2024-12-03 02:20:20 +01:00
parent 63998f71ec
commit fd0a472468
6 changed files with 295 additions and 116 deletions

View File

@@ -14,6 +14,7 @@ import { CheckCircle2, ExternalLink, Globe, Terminal } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
import { toast } from "sonner"; import { toast } from "sonner";
import { DockerTerminalModal } from "../../settings/web-server/docker-terminal-modal"; import { DockerTerminalModal } from "../../settings/web-server/docker-terminal-modal";
import { StartCompose } from "../start-compose";
import { DeployCompose } from "./deploy-compose"; import { DeployCompose } from "./deploy-compose";
import { RedbuildCompose } from "./rebuild-compose"; import { RedbuildCompose } from "./rebuild-compose";
import { StopCompose } from "./stop-compose"; import { StopCompose } from "./stop-compose";
@@ -71,7 +72,10 @@ export const ComposeActions = ({ composeId }: Props) => {
Autodeploy {data?.autoDeploy && <CheckCircle2 className="size-4" />} Autodeploy {data?.autoDeploy && <CheckCircle2 className="size-4" />}
</Toggle> </Toggle>
<RedbuildCompose composeId={composeId} /> <RedbuildCompose composeId={composeId} />
{data?.composeType === "docker-compose" && ( {data?.composeType === "docker-compose" &&
data?.composeStatus === "idle" ? (
<StartCompose composeId={composeId} />
) : (
<StopCompose composeId={composeId} /> <StopCompose composeId={composeId} />
)} )}

View File

@@ -0,0 +1,65 @@
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import { Button } from "@/components/ui/button";
import { api } from "@/utils/api";
import { CheckCircle2 } from "lucide-react";
import { toast } from "sonner";
interface Props {
composeId: string;
}
export const StartCompose = ({ composeId }: Props) => {
const { mutateAsync, isLoading } = api.compose.start.useMutation();
const utils = api.useUtils();
return (
<AlertDialog>
<AlertDialogTrigger asChild>
<Button variant="secondary" isLoading={isLoading}>
Start
<CheckCircle2 className="size-4" />
</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>
Are you sure to start the compose?
</AlertDialogTitle>
<AlertDialogDescription>
This will start the compose
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction
onClick={async () => {
await mutateAsync({
composeId,
})
.then(async () => {
await utils.compose.one.invalidate({
composeId,
});
toast.success("Compose started succesfully");
})
.catch(() => {
toast.error("Error to start the Compose");
});
}}
>
Confirm
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
);
};

View File

@@ -0,0 +1,65 @@
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import { Button } from "@/components/ui/button";
import { api } from "@/utils/api";
import { Ban } from "lucide-react";
import { toast } from "sonner";
interface Props {
composeId: string;
}
export const StopCompose = ({ composeId }: Props) => {
const { mutateAsync, isLoading } = api.compose.stop.useMutation();
const utils = api.useUtils();
return (
<AlertDialog>
<AlertDialogTrigger asChild>
<Button variant="destructive" isLoading={isLoading}>
Stop
<Ban className="size-4" />
</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>
Are you absolutely sure to stop the compose?
</AlertDialogTitle>
<AlertDialogDescription>
This will stop the compose
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction
onClick={async () => {
await mutateAsync({
composeId,
})
.then(async () => {
await utils.compose.one.invalidate({
composeId,
});
toast.success("Compose stopped succesfully");
})
.catch(() => {
toast.error("Error to stop the Compose");
});
}}
>
Confirm
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
);
};

View File

@@ -11,7 +11,7 @@ import { extractCommitMessage, extractHash } from "./[refreshToken]";
export default async function handler( export default async function handler(
req: NextApiRequest, req: NextApiRequest,
res: NextApiResponse res: NextApiResponse,
) { ) {
const signature = req.headers["x-hub-signature-256"]; const signature = req.headers["x-hub-signature-256"];
const githubBody = req.body; const githubBody = req.body;
@@ -40,7 +40,7 @@ export default async function handler(
const verified = await webhooks.verify( const verified = await webhooks.verify(
JSON.stringify(githubBody), JSON.stringify(githubBody),
signature as string signature as string,
); );
if (!verified) { if (!verified) {
@@ -69,7 +69,7 @@ export default async function handler(
eq(applications.sourceType, "github"), eq(applications.sourceType, "github"),
eq(applications.autoDeploy, true), eq(applications.autoDeploy, true),
eq(applications.branch, branchName), eq(applications.branch, branchName),
eq(applications.repository, repository) eq(applications.repository, repository),
), ),
}); });
@@ -94,7 +94,7 @@ export default async function handler(
{ {
removeOnComplete: true, removeOnComplete: true,
removeOnFail: true, removeOnFail: true,
} },
); );
} }
@@ -103,7 +103,7 @@ export default async function handler(
eq(compose.sourceType, "github"), eq(compose.sourceType, "github"),
eq(compose.autoDeploy, true), eq(compose.autoDeploy, true),
eq(compose.branch, branchName), eq(compose.branch, branchName),
eq(compose.repository, repository) eq(compose.repository, repository),
), ),
}); });
@@ -129,7 +129,7 @@ export default async function handler(
{ {
removeOnComplete: true, removeOnComplete: true,
removeOnFail: true, removeOnFail: true,
} },
); );
} }

View File

@@ -48,6 +48,7 @@ import {
removeCompose, removeCompose,
removeComposeDirectory, removeComposeDirectory,
removeDeploymentsByComposeId, removeDeploymentsByComposeId,
startCompose,
stopCompose, stopCompose,
updateCompose, updateCompose,
} from "@dokploy/server"; } from "@dokploy/server";
@@ -309,6 +310,20 @@ export const composeRouter = createTRPCRouter({
} }
await stopCompose(input.composeId); await stopCompose(input.composeId);
return true;
}),
start: protectedProcedure
.input(apiFindCompose)
.mutation(async ({ input, ctx }) => {
const compose = await findComposeById(input.composeId);
if (compose.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to stop this compose",
});
}
await startCompose(input.composeId);
return true; return true;
}), }),
getDefaultCommand: protectedProcedure getDefaultCommand: protectedProcedure

View File

@@ -463,6 +463,36 @@ export const removeCompose = async (compose: Compose) => {
return true; return true;
}; };
export const startCompose = async (composeId: string) => {
const compose = await findComposeById(composeId);
try {
const { COMPOSE_PATH } = paths(!!compose.serverId);
if (compose.composeType === "docker-compose") {
if (compose.serverId) {
await execAsyncRemote(
compose.serverId,
`cd ${join(COMPOSE_PATH, compose.appName, "code")} && docker compose -p ${compose.appName} up -d`,
);
} else {
await execAsync(`docker compose -p ${compose.appName} up -d`, {
cwd: join(COMPOSE_PATH, compose.appName, "code"),
});
}
}
await updateCompose(composeId, {
composeStatus: "done",
});
} catch (error) {
await updateCompose(composeId, {
composeStatus: "idle",
});
throw error;
}
return true;
};
export const stopCompose = async (composeId: string) => { export const stopCompose = async (composeId: string) => {
const compose = await findComposeById(composeId); const compose = await findComposeById(composeId);
try { try {