diff --git a/client/src/App.tsx b/client/src/App.tsx index 30f9f980..e15711cf 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -49,6 +49,7 @@ import useUser from "./apps/Auth/hooks/useUser"; import AccountEmails from "./apps/Auth/pages/Account/AccountEmails"; import { getAuthToken } from "./backend/server"; import AccountTheme from "./apps/Auth/pages/Account/AccountTheme"; +import ContainerPorts from "./apps/Containers/pages/ContainerPorts/ContainerPorts"; const queryClient = new QueryClient(); @@ -179,6 +180,10 @@ function AllRoutes() { path="/containers/:uuid/environment" element={} /> + } + /> } diff --git a/client/src/apps/Containers/backend/api.ts b/client/src/apps/Containers/backend/api.ts index f0bb151f..bc3b3cff 100644 --- a/client/src/apps/Containers/backend/api.ts +++ b/client/src/apps/Containers/backend/api.ts @@ -77,6 +77,11 @@ const saveEnv = (id: string, env: EnvVariables) => { return server.patch(`/containers/${id}/environment`, { env }); }; +const getContainerPorts = async (id: string) => { + const { data } = await server.get(`/containers/${id}/ports`); + return data; +}; + const getDocker = async (id: string) => { const { data } = await server.get( `/containers/${id}/docker` @@ -111,6 +116,7 @@ export const API = { getLogs, getContainerEnvironment, saveEnv, + getContainerPorts, getDockerInfo: getDocker, recreateDocker, updateService, diff --git a/client/src/apps/Containers/hooks/useContainer.tsx b/client/src/apps/Containers/hooks/useContainer.tsx index 3cc02e14..542285b6 100644 --- a/client/src/apps/Containers/hooks/useContainer.tsx +++ b/client/src/apps/Containers/hooks/useContainer.tsx @@ -36,3 +36,15 @@ export function useContainerEnv(id?: string) { errorEnv: queryEnv.error, }; } + +export function useContainerPorts(id?: string) { + const queryPorts = useQuery({ + queryKey: ["container_ports", id], + queryFn: () => API.getContainerPorts(id), + }); + return { + ports: queryPorts.data, + isLoadingPorts: queryPorts.isLoading, + errorPorts: queryPorts.error, + }; +} diff --git a/client/src/apps/Containers/pages/Container/Container.tsx b/client/src/apps/Containers/pages/Container/Container.tsx index b5c90e31..2ac9dc3c 100644 --- a/client/src/apps/Containers/pages/Container/Container.tsx +++ b/client/src/apps/Containers/pages/Container/Container.tsx @@ -25,6 +25,7 @@ import { Cube, Gear, House, + ShareNetwork, TerminalWindow, Textbox, Trash, @@ -107,6 +108,11 @@ export default function ContainerDetails() { icon={} link={l(`/containers/${uuid}/environment`)} /> + } + link={l(`/containers/${uuid}/ports`)} + /> {container?.databases && ( + Ports + + + + + + Port inside container + Port outside container + + + + {ports?.map((port, i) => ( + + + + + + + + + ))} + +
+ + ); +} diff --git a/server/apps/containers/app.go b/server/apps/containers/app.go index a126a98d..b6b71504 100644 --- a/server/apps/containers/app.go +++ b/server/apps/containers/app.go @@ -171,6 +171,12 @@ func (a *App) InitializeRouter(r *fizz.RouterGroup) error { fizz.Response("500", "", nil, nil, map[string]interface{}{"error": "failed to patch container environment"}), }, containersHandler.PatchEnvironment()) + containers.GET("/:container_id/ports", []fizz.OperationOption{ + fizz.ID("getContainerPorts"), + fizz.Summary("Get container ports"), + fizz.Response("404", "Container not found", nil, nil, map[string]interface{}{"error": "container not found"}), + }, containersHandler.GetContainerPorts()) + containers.GET("/:container_id/events", []fizz.OperationOption{ fizz.ID("eventsContainer"), fizz.Summary("Get container events"), diff --git a/server/apps/containers/core/port/handlers.go b/server/apps/containers/core/port/handlers.go index 8d7534e8..56af6b88 100644 --- a/server/apps/containers/core/port/handlers.go +++ b/server/apps/containers/core/port/handlers.go @@ -16,6 +16,7 @@ type ( AddContainerTag() gin.HandlerFunc GetContainerEnv() gin.HandlerFunc PatchEnvironment() gin.HandlerFunc + GetContainerPorts() gin.HandlerFunc GetDocker() gin.HandlerFunc RecreateDocker() gin.HandlerFunc GetLogs() gin.HandlerFunc diff --git a/server/apps/containers/core/port/services.go b/server/apps/containers/core/port/services.go index 912cd377..519f48f6 100644 --- a/server/apps/containers/core/port/services.go +++ b/server/apps/containers/core/port/services.go @@ -30,6 +30,7 @@ type ( SetDatabases(ctx context.Context, c *types.Container, databases map[string]uuid.UUID, options map[string]*types.SetDatabasesOptions) error GetContainerEnv(ctx context.Context, id uuid.UUID) (types.EnvVariables, error) SaveEnv(ctx context.Context, id uuid.UUID, env types.EnvVariables) error + GetContainerPorts(ctx context.Context, id uuid.UUID) (types.Ports, error) GetAllVersions(ctx context.Context, id uuid.UUID, useCache bool) ([]string, error) GetContainerInfo(ctx context.Context, id uuid.UUID) (map[string]any, error) WaitStatus(ctx context.Context, id uuid.UUID, status string) error diff --git a/server/apps/containers/core/port/services_mock.go b/server/apps/containers/core/port/services_mock.go index aef3ed7d..e92d078f 100644 --- a/server/apps/containers/core/port/services_mock.go +++ b/server/apps/containers/core/port/services_mock.go @@ -94,6 +94,11 @@ func (m *MockContainerService) GetContainerEnv(ctx context.Context, id uuid.UUID return args.Get(0).(types.EnvVariables), args.Error(1) } +func (m *MockContainerService) GetContainerPorts(ctx context.Context, id uuid.UUID) (types.Ports, error) { + args := m.Called(ctx, id) + return args.Get(0).(types.Ports), args.Error(1) +} + func (m *MockContainerService) RecreateContainer(ctx context.Context, uuid uuid.UUID) error { args := m.Called(ctx, uuid) return args.Error(0) diff --git a/server/apps/containers/core/service/container.go b/server/apps/containers/core/service/container.go index ab43faba..9933dfe7 100644 --- a/server/apps/containers/core/service/container.go +++ b/server/apps/containers/core/service/container.go @@ -623,6 +623,10 @@ func (s *containerService) GetContainerEnv(ctx context.Context, id uuid.UUID) (t return s.vars.GetContainerVariables(ctx, id) } +func (s *containerService) GetContainerPorts(ctx context.Context, id uuid.UUID) (types.Ports, error) { + return s.ports.GetContainerPorts(ctx, id) +} + // remapDatabaseEnv remaps the environment variables of a container. func (s *containerService) remapDatabaseEnv(ctx context.Context, c *types.Container, options map[string]*types.SetDatabasesOptions) error { for databaseID, databaseContainerID := range c.Databases { diff --git a/server/apps/containers/handler/container.go b/server/apps/containers/handler/container.go index e69819da..470eebef 100644 --- a/server/apps/containers/handler/container.go +++ b/server/apps/containers/handler/container.go @@ -167,6 +167,17 @@ func (h *containerHandler) PatchEnvironment() gin.HandlerFunc { }, http.StatusOK) } +type GetContainerPortsParams struct { + ContainerID uuid.NullUUID `path:"container_id"` +} + +func (h *containerHandler) GetContainerPorts() gin.HandlerFunc { + return tonic.Handler(func(ctx *gin.Context, params *GetContainerPortsParams) (types.Ports, error) { + return h.containerService.GetContainerPorts(ctx, params.ContainerID.UUID) + }, http.StatusOK) + +} + func (h *containerHandler) GetDocker() gin.HandlerFunc { return tonic.Handler(func(ctx *gin.Context, params *GetContainerParams) (map[string]any, error) { return h.containerService.GetContainerInfo(ctx, params.ContainerID.UUID)