mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
feat(multi-server): add docker containers view to servers
This commit is contained in:
@@ -11,12 +11,14 @@ import { api } from "@/utils/api";
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
containerId: string;
|
containerId: string;
|
||||||
|
serverId?: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ShowContainerConfig = ({ containerId }: Props) => {
|
export const ShowContainerConfig = ({ containerId, serverId }: Props) => {
|
||||||
const { data } = api.docker.getConfig.useQuery(
|
const { data } = api.docker.getConfig.useQuery(
|
||||||
{
|
{
|
||||||
containerId,
|
containerId,
|
||||||
|
serverId,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
enabled: !!containerId,
|
enabled: !!containerId,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import "@xterm/xterm/css/xterm.css";
|
|||||||
interface Props {
|
interface Props {
|
||||||
id: string;
|
id: string;
|
||||||
containerId: string;
|
containerId: string;
|
||||||
serverId?: string;
|
serverId?: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DockerLogsId: React.FC<Props> = ({
|
export const DockerLogsId: React.FC<Props> = ({
|
||||||
|
|||||||
@@ -22,9 +22,14 @@ export const DockerLogsId = dynamic(
|
|||||||
interface Props {
|
interface Props {
|
||||||
containerId: string;
|
containerId: string;
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
|
serverId?: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ShowDockerModalLogs = ({ containerId, children }: Props) => {
|
export const ShowDockerModalLogs = ({
|
||||||
|
containerId,
|
||||||
|
children,
|
||||||
|
serverId,
|
||||||
|
}: Props) => {
|
||||||
return (
|
return (
|
||||||
<Dialog>
|
<Dialog>
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
@@ -41,7 +46,11 @@ export const ShowDockerModalLogs = ({ containerId, children }: Props) => {
|
|||||||
<DialogDescription>View the logs for {containerId}</DialogDescription>
|
<DialogDescription>View the logs for {containerId}</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<div className="flex flex-col gap-4 pt-2.5">
|
<div className="flex flex-col gap-4 pt-2.5">
|
||||||
<DockerLogsId id="terminal" containerId={containerId || ""} />
|
<DockerLogsId
|
||||||
|
id="terminal"
|
||||||
|
containerId={containerId || ""}
|
||||||
|
serverId={serverId}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|||||||
@@ -114,10 +114,16 @@ export const columns: ColumnDef<Container>[] = [
|
|||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent align="end">
|
<DropdownMenuContent align="end">
|
||||||
<DropdownMenuLabel>Actions</DropdownMenuLabel>
|
<DropdownMenuLabel>Actions</DropdownMenuLabel>
|
||||||
<ShowDockerModalLogs containerId={container.containerId}>
|
<ShowDockerModalLogs
|
||||||
|
containerId={container.containerId}
|
||||||
|
serverId={container.serverId}
|
||||||
|
>
|
||||||
View Logs
|
View Logs
|
||||||
</ShowDockerModalLogs>
|
</ShowDockerModalLogs>
|
||||||
<ShowContainerConfig containerId={container.containerId} />
|
<ShowContainerConfig
|
||||||
|
containerId={container.containerId}
|
||||||
|
serverId={container.serverId}
|
||||||
|
/>
|
||||||
<DockerTerminalModal containerId={container.containerId}>
|
<DockerTerminalModal containerId={container.containerId}>
|
||||||
Terminal
|
Terminal
|
||||||
</DockerTerminalModal>
|
</DockerTerminalModal>
|
||||||
|
|||||||
@@ -34,8 +34,14 @@ export type Container = NonNullable<
|
|||||||
RouterOutputs["docker"]["getContainers"]
|
RouterOutputs["docker"]["getContainers"]
|
||||||
>[0];
|
>[0];
|
||||||
|
|
||||||
export const ShowContainers = () => {
|
interface Props {
|
||||||
const { data, isLoading } = api.docker.getContainers.useQuery();
|
serverId?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ShowContainers = ({ serverId }: Props) => {
|
||||||
|
const { data, isLoading } = api.docker.getContainers.useQuery({
|
||||||
|
serverId,
|
||||||
|
});
|
||||||
const [sorting, setSorting] = React.useState<SortingState>([]);
|
const [sorting, setSorting] = React.useState<SortingState>([]);
|
||||||
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
|
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
|
||||||
[],
|
[],
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle,
|
||||||
|
DialogTrigger,
|
||||||
|
} from "@/components/ui/dialog";
|
||||||
|
import { DropdownMenuItem } from "@/components/ui/dropdown-menu";
|
||||||
|
import { ContainerIcon, FileTextIcon } from "lucide-react";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { ShowTraefikSystem } from "../../file-system/show-traefik-system";
|
||||||
|
import { ShowContainers } from "../../docker/show/show-containers";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
serverId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ShowDockerContainersModal = ({ serverId }: Props) => {
|
||||||
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
||||||
|
<DialogTrigger asChild>
|
||||||
|
<DropdownMenuItem
|
||||||
|
className="w-full cursor-pointer "
|
||||||
|
onSelect={(e) => e.preventDefault()}
|
||||||
|
>
|
||||||
|
Show Docker Containers
|
||||||
|
</DropdownMenuItem>
|
||||||
|
</DialogTrigger>
|
||||||
|
<DialogContent className="sm:max-w-7xl overflow-y-auto max-h-screen ">
|
||||||
|
<DialogHeader>
|
||||||
|
<div className="flex flex-col gap-1.5">
|
||||||
|
<DialogTitle className="flex items-center gap-2">
|
||||||
|
<ContainerIcon className="size-5" /> Docker Containers
|
||||||
|
</DialogTitle>
|
||||||
|
<p className="text-muted-foreground text-sm">
|
||||||
|
See all the containers of your remote server
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</DialogHeader>
|
||||||
|
|
||||||
|
<div className="grid w-full gap-1">
|
||||||
|
<ShowContainers serverId={serverId} />
|
||||||
|
{/* <ShowTraefikSystem serverId={serverId} /> */}
|
||||||
|
</div>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle,
|
||||||
|
DialogTrigger,
|
||||||
|
} from "@/components/ui/dialog";
|
||||||
|
import { DropdownMenuItem } from "@/components/ui/dropdown-menu";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import {
|
||||||
|
Card,
|
||||||
|
CardContent,
|
||||||
|
CardDescription,
|
||||||
|
CardFooter,
|
||||||
|
CardHeader,
|
||||||
|
CardTitle,
|
||||||
|
} from "@/components/ui/card";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
|
import { Label } from "@/components/ui/label";
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from "@/components/ui/select";
|
||||||
|
import { TraefikActions } from "./traefik-actions";
|
||||||
|
interface Props {
|
||||||
|
serverId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ShowServer = ({ serverId }: Props) => {
|
||||||
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
return (
|
||||||
|
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
||||||
|
<DialogTrigger asChild>
|
||||||
|
<DropdownMenuItem
|
||||||
|
className="w-full cursor-pointer "
|
||||||
|
onSelect={(e) => e.preventDefault()}
|
||||||
|
>
|
||||||
|
View Actions
|
||||||
|
</DropdownMenuItem>
|
||||||
|
</DialogTrigger>
|
||||||
|
<DialogContent className="sm:max-w-6xl overflow-y-auto max-h-screen ">
|
||||||
|
<DialogHeader>
|
||||||
|
<div className="flex flex-col gap-1.5">
|
||||||
|
<DialogTitle className="flex items-center gap-2">
|
||||||
|
Server Actions
|
||||||
|
</DialogTitle>
|
||||||
|
<p className="text-muted-foreground text-sm">
|
||||||
|
View all the actions you can do with this server remotely
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</DialogHeader>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-3 w-full gap-1">
|
||||||
|
<Card className="bg-transparent">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle className="text-xl">Traefik</CardTitle>
|
||||||
|
<CardDescription>
|
||||||
|
Deploy your new project in one-click.
|
||||||
|
</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<TraefikActions serverId={serverId} />
|
||||||
|
</CardContent>
|
||||||
|
<CardFooter className="flex justify-between">
|
||||||
|
<Button variant="outline">Cancel</Button>
|
||||||
|
<Button>Deploy</Button>
|
||||||
|
</CardFooter>
|
||||||
|
</Card>
|
||||||
|
{/* <ShowTraefikSystem serverId={serverId} /> */}
|
||||||
|
</div>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -31,6 +31,8 @@ import { ShowTraefikFileSystemModal } from "./show-traefik-file-system-modal";
|
|||||||
import { ShowModalLogs } from "../web-server/show-modal-logs";
|
import { ShowModalLogs } from "../web-server/show-modal-logs";
|
||||||
import { ToggleTraefikDashboard } from "./toggle-traefik-dashboard";
|
import { ToggleTraefikDashboard } from "./toggle-traefik-dashboard";
|
||||||
import { EditTraefikEnv } from "../web-server/edit-traefik-env";
|
import { EditTraefikEnv } from "../web-server/edit-traefik-env";
|
||||||
|
import { ShowServer } from "./show-server";
|
||||||
|
import { ShowDockerContainersModal } from "./show-docker-containers-modal";
|
||||||
export const ShowServers = () => {
|
export const ShowServers = () => {
|
||||||
const { data, refetch } = api.server.all.useQuery();
|
const { data, refetch } = api.server.all.useQuery();
|
||||||
const { mutateAsync } = api.server.remove.useMutation();
|
const { mutateAsync } = api.server.remove.useMutation();
|
||||||
@@ -171,6 +173,7 @@ export const ShowServers = () => {
|
|||||||
<SetupServer serverId={server.serverId} />
|
<SetupServer serverId={server.serverId} />
|
||||||
|
|
||||||
<UpdateServer serverId={server.serverId} />
|
<UpdateServer serverId={server.serverId} />
|
||||||
|
<ShowServer serverId={server.serverId} />
|
||||||
<DialogAction
|
<DialogAction
|
||||||
title={"Delete Server"}
|
title={"Delete Server"}
|
||||||
description="This will delete the server and all associated data"
|
description="This will delete the server and all associated data"
|
||||||
@@ -196,6 +199,7 @@ export const ShowServers = () => {
|
|||||||
Delete Server
|
Delete Server
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</DialogAction>
|
</DialogAction>
|
||||||
|
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<DropdownMenuLabel>Traefik</DropdownMenuLabel>
|
<DropdownMenuLabel>Traefik</DropdownMenuLabel>
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
@@ -216,6 +220,9 @@ export const ShowServers = () => {
|
|||||||
<ShowTraefikFileSystemModal
|
<ShowTraefikFileSystemModal
|
||||||
serverId={server.serverId}
|
serverId={server.serverId}
|
||||||
/>
|
/>
|
||||||
|
<ShowDockerContainersModal
|
||||||
|
serverId={server.serverId}
|
||||||
|
/>
|
||||||
<ShowModalLogs
|
<ShowModalLogs
|
||||||
appName="dokploy-traefik"
|
appName="dokploy-traefik"
|
||||||
serverId={server.serverId}
|
serverId={server.serverId}
|
||||||
|
|||||||
@@ -0,0 +1,135 @@
|
|||||||
|
import { api } from "@/utils/api";
|
||||||
|
import {
|
||||||
|
DropdownMenu,
|
||||||
|
DropdownMenuContent,
|
||||||
|
DropdownMenuGroup,
|
||||||
|
DropdownMenuItem,
|
||||||
|
DropdownMenuLabel,
|
||||||
|
DropdownMenuSeparator,
|
||||||
|
DropdownMenuTrigger,
|
||||||
|
} from "@/components/ui/dropdown-menu";
|
||||||
|
import { toast } from "sonner";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { ShowModalLogs } from "../web-server/show-modal-logs";
|
||||||
|
import { DockerTerminalModal } from "../web-server/docker-terminal-modal";
|
||||||
|
import { EditTraefikEnv } from "../web-server/edit-traefik-env";
|
||||||
|
import { ShowMainTraefikConfig } from "../web-server/show-main-traefik-config";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
serverId?: string;
|
||||||
|
}
|
||||||
|
export const TraefikActions = ({ serverId }: Props) => {
|
||||||
|
api.settings.reloadServer.useMutation();
|
||||||
|
const { mutateAsync: reloadTraefik, isLoading: reloadTraefikIsLoading } =
|
||||||
|
api.settings.reloadTraefik.useMutation();
|
||||||
|
const { mutateAsync: cleanAll, isLoading: cleanAllIsLoading } =
|
||||||
|
api.settings.cleanAll.useMutation();
|
||||||
|
const { mutateAsync: toggleDashboard, isLoading: toggleDashboardIsLoading } =
|
||||||
|
api.settings.toggleDashboard.useMutation();
|
||||||
|
|
||||||
|
const {
|
||||||
|
mutateAsync: cleanStoppedContainers,
|
||||||
|
isLoading: cleanStoppedContainersIsLoading,
|
||||||
|
} = api.settings.cleanStoppedContainers.useMutation();
|
||||||
|
|
||||||
|
const { data: dokployVersion } = api.settings.getDokployVersion.useQuery();
|
||||||
|
|
||||||
|
const { mutateAsync: updateDockerCleanup } =
|
||||||
|
api.settings.updateDockerCleanup.useMutation();
|
||||||
|
|
||||||
|
const { data: haveTraefikDashboardPortEnabled, refetch: refetchDashboard } =
|
||||||
|
api.settings.haveTraefikDashboardPortEnabled.useQuery();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DropdownMenu>
|
||||||
|
<DropdownMenuTrigger
|
||||||
|
asChild
|
||||||
|
disabled={reloadTraefikIsLoading || toggleDashboardIsLoading}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
isLoading={reloadTraefikIsLoading || toggleDashboardIsLoading}
|
||||||
|
variant="outline"
|
||||||
|
>
|
||||||
|
Traefik
|
||||||
|
</Button>
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
<DropdownMenuContent className="w-56" align="start">
|
||||||
|
<DropdownMenuLabel>Actions</DropdownMenuLabel>
|
||||||
|
<DropdownMenuSeparator />
|
||||||
|
<DropdownMenuGroup>
|
||||||
|
<DropdownMenuItem
|
||||||
|
onClick={async () => {
|
||||||
|
await reloadTraefik({
|
||||||
|
serverId: serverId,
|
||||||
|
})
|
||||||
|
.then(async () => {
|
||||||
|
toast.success("Traefik Reloaded");
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
toast.error("Error to reload the traefik");
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span>Reload</span>
|
||||||
|
</DropdownMenuItem>
|
||||||
|
<ShowModalLogs appName="dokploy-traefik">
|
||||||
|
<span>Watch logs</span>
|
||||||
|
</ShowModalLogs>
|
||||||
|
{!serverId && (
|
||||||
|
<ShowMainTraefikConfig>
|
||||||
|
<DropdownMenuItem
|
||||||
|
onSelect={(e) => e.preventDefault()}
|
||||||
|
className="w-full cursor-pointer space-x-3"
|
||||||
|
>
|
||||||
|
<span>View Traefik config</span>
|
||||||
|
</DropdownMenuItem>
|
||||||
|
</ShowMainTraefikConfig>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<EditTraefikEnv serverId={serverId}>
|
||||||
|
<DropdownMenuItem
|
||||||
|
onSelect={(e) => e.preventDefault()}
|
||||||
|
className="w-full cursor-pointer space-x-3"
|
||||||
|
>
|
||||||
|
<span>Modify Env</span>
|
||||||
|
</DropdownMenuItem>
|
||||||
|
</EditTraefikEnv>
|
||||||
|
|
||||||
|
<DropdownMenuItem
|
||||||
|
onClick={async () => {
|
||||||
|
await toggleDashboard({
|
||||||
|
enableDashboard: !haveTraefikDashboardPortEnabled,
|
||||||
|
serverId: serverId,
|
||||||
|
})
|
||||||
|
.then(async () => {
|
||||||
|
toast.success(
|
||||||
|
`${haveTraefikDashboardPortEnabled ? "Disabled" : "Enabled"} Dashboard`,
|
||||||
|
);
|
||||||
|
refetchDashboard();
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
toast.error(
|
||||||
|
`${haveTraefikDashboardPortEnabled ? "Disabled" : "Enabled"} Dashboard`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
className="w-full cursor-pointer space-x-3"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
{haveTraefikDashboardPortEnabled ? "Disable" : "Enable"} Dashboard
|
||||||
|
</span>
|
||||||
|
</DropdownMenuItem>
|
||||||
|
|
||||||
|
<DockerTerminalModal appName="dokploy-traefik" serverId={serverId}>
|
||||||
|
<DropdownMenuItem
|
||||||
|
className="w-full cursor-pointer space-x-3"
|
||||||
|
onSelect={(e) => e.preventDefault()}
|
||||||
|
>
|
||||||
|
<span>Enter the terminal</span>
|
||||||
|
</DropdownMenuItem>
|
||||||
|
</DockerTerminalModal>
|
||||||
|
</DropdownMenuGroup>
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -9,9 +9,15 @@ import {
|
|||||||
import { createTRPCRouter, protectedProcedure } from "../trpc";
|
import { createTRPCRouter, protectedProcedure } from "../trpc";
|
||||||
|
|
||||||
export const dockerRouter = createTRPCRouter({
|
export const dockerRouter = createTRPCRouter({
|
||||||
getContainers: protectedProcedure.query(async () => {
|
getContainers: protectedProcedure
|
||||||
return await getContainers();
|
.input(
|
||||||
}),
|
z.object({
|
||||||
|
serverId: z.string().optional(),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.query(async ({ input }) => {
|
||||||
|
return await getContainers(input.serverId);
|
||||||
|
}),
|
||||||
|
|
||||||
restartContainer: protectedProcedure
|
restartContainer: protectedProcedure
|
||||||
.input(
|
.input(
|
||||||
@@ -27,10 +33,11 @@ export const dockerRouter = createTRPCRouter({
|
|||||||
.input(
|
.input(
|
||||||
z.object({
|
z.object({
|
||||||
containerId: z.string().min(1),
|
containerId: z.string().min(1),
|
||||||
|
serverId: z.string().optional(),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.query(async ({ input }) => {
|
.query(async ({ input }) => {
|
||||||
return await getConfig(input.containerId);
|
return await getConfig(input.containerId, input.serverId);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
getContainersByAppNameMatch: protectedProcedure
|
getContainersByAppNameMatch: protectedProcedure
|
||||||
|
|||||||
@@ -1,11 +1,22 @@
|
|||||||
import { execAsync, execAsyncRemote } from "@/server/utils/process/execAsync";
|
import { execAsync, execAsyncRemote } from "@/server/utils/process/execAsync";
|
||||||
|
|
||||||
export const getContainers = async () => {
|
export const getContainers = async (serverId?: string | null) => {
|
||||||
try {
|
try {
|
||||||
const { stdout, stderr } = await execAsync(
|
const command =
|
||||||
"docker ps -a --format 'CONTAINER ID : {{.ID}} | Name: {{.Names}} | Image: {{.Image}} | Ports: {{.Ports}} | State: {{.State}} | Status: {{.Status}}'",
|
"docker ps -a --format 'CONTAINER ID : {{.ID}} | Name: {{.Names}} | Image: {{.Image}} | Ports: {{.Ports}} | State: {{.State}} | Status: {{.Status}}'";
|
||||||
);
|
let stdout = "";
|
||||||
|
let stderr = "";
|
||||||
|
|
||||||
|
if (serverId) {
|
||||||
|
const result = await execAsyncRemote(serverId, command);
|
||||||
|
|
||||||
|
stdout = result.stdout;
|
||||||
|
stderr = result.stderr;
|
||||||
|
} else {
|
||||||
|
const result = await execAsync(command);
|
||||||
|
stdout = result.stdout;
|
||||||
|
stderr = result.stderr;
|
||||||
|
}
|
||||||
if (stderr) {
|
if (stderr) {
|
||||||
console.error(`Error: ${stderr}`);
|
console.error(`Error: ${stderr}`);
|
||||||
return;
|
return;
|
||||||
@@ -41,6 +52,7 @@ export const getContainers = async () => {
|
|||||||
ports,
|
ports,
|
||||||
state,
|
state,
|
||||||
status,
|
status,
|
||||||
|
serverId,
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.filter((container) => !container.name.includes("dokploy"));
|
.filter((container) => !container.name.includes("dokploy"));
|
||||||
@@ -49,11 +61,23 @@ export const getContainers = async () => {
|
|||||||
} catch (error) {}
|
} catch (error) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getConfig = async (containerId: string) => {
|
export const getConfig = async (
|
||||||
|
containerId: string,
|
||||||
|
serverId?: string | null,
|
||||||
|
) => {
|
||||||
try {
|
try {
|
||||||
const { stdout, stderr } = await execAsync(
|
const command = `docker inspect ${containerId} --format='{{json .}}'`;
|
||||||
`docker inspect ${containerId} --format='{{json .}}'`,
|
let stdout = "";
|
||||||
);
|
let stderr = "";
|
||||||
|
if (serverId) {
|
||||||
|
const result = await execAsyncRemote(serverId, command);
|
||||||
|
stdout = result.stdout;
|
||||||
|
stderr = result.stderr;
|
||||||
|
} else {
|
||||||
|
const result = await execAsync(command);
|
||||||
|
stdout = result.stdout;
|
||||||
|
stderr = result.stderr;
|
||||||
|
}
|
||||||
|
|
||||||
if (stderr) {
|
if (stderr) {
|
||||||
console.error(`Error: ${stderr}`);
|
console.error(`Error: ${stderr}`);
|
||||||
|
|||||||
Reference in New Issue
Block a user