From afa0173350a0e498ab128b70fad20aed834c4be6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Quentin=20Guid=C3=A9e?= Date: Tue, 12 Dec 2023 10:05:32 -0500 Subject: [PATCH 1/6] First draft of the new Vertex Containers compatibility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Quentin Guidée --- .../Containers/backend/api.ts} | 81 +++++++------------ src/apps/Containers/backend/models.ts | 70 ++++++++++++++++ .../Containers/backend}/service.ts | 0 .../EnvVariableInput/EnvVariableInput.tsx | 4 +- .../components/SelectTags/SelectTags.tsx | 8 +- src/apps/Containers/hooks/useContainer.tsx | 20 ++--- src/apps/Containers/hooks/useContainers.tsx | 8 +- .../Containers/pages/Container/Container.tsx | 37 ++++----- .../ContainerDetailsDatabase.tsx | 6 +- .../pages/ContainerDocker/ContainerDocker.tsx | 6 +- .../pages/ContainerEnv/ContainerEnv.tsx | 56 +++---------- .../pages/ContainerHome/ContainerHome.tsx | 53 +----------- .../ContainerSettings/ContainerSettings.tsx | 14 ++-- .../pages/ContainerUpdate/ContainerUpdate.tsx | 6 +- .../pages/ContainersApp/ContainersApp.tsx | 18 ++--- .../pages/ContainersStore/ContainersStore.tsx | 35 ++++---- src/apps/Sql/Installer/SqlInstaller.tsx | 2 +- src/apps/Sql/SqlDatabase/SqlDatabase.tsx | 8 +- src/backend/api/backend.ts | 2 - src/backend/api/vxServiceEditor.ts | 2 +- src/components/Container/Container.tsx | 19 ++--- .../ContainerInstaller/ContainerInstaller.tsx | 22 ++--- src/components/Service/Service.tsx | 2 +- .../ServiceInstallPopup.tsx | 2 +- src/components/ServiceLogo/ServiceLogo.tsx | 2 +- src/models/container.ts | 41 ---------- 26 files changed, 213 insertions(+), 311 deletions(-) rename src/{backend/api/vxContainers.ts => apps/Containers/backend/api.ts} (57%) create mode 100644 src/apps/Containers/backend/models.ts rename src/{models => apps/Containers/backend}/service.ts (100%) diff --git a/src/backend/api/vxContainers.ts b/src/apps/Containers/backend/api.ts similarity index 57% rename from src/backend/api/vxContainers.ts rename to src/apps/Containers/backend/api.ts index 3f6d94a6..7d4b8c8c 100644 --- a/src/backend/api/vxContainers.ts +++ b/src/apps/Containers/backend/api.ts @@ -1,8 +1,13 @@ -import { Container, ContainerQuery, Containers } from "../../models/container"; -import { Env, Service } from "../../models/service"; -import { DockerContainerInfo } from "../../models/docker"; - -import { createServer } from "../server"; +import { createServer } from "../../../backend/server"; +import { + Container, + ContainerQuery, + Containers, + EnvVariables, + Tags, +} from "./models"; +import { DockerContainerInfo } from "../../../models/docker"; +import { Service } from "./service"; // @ts-ignore const server = createServer(window.api_urls.containers); @@ -13,7 +18,7 @@ const getAllContainers = async () => { }; const getAllTags = async () => { - const { data } = await server.get(`/containers/tags`); + const { data } = await server.get(`/containers/tags`); return data; }; @@ -60,7 +65,7 @@ const getLogs = async (id: string) => { return data; }; -const saveEnv = (id: string, env: Env) => { +const saveEnv = (id: string, env: EnvVariables) => { return server.patch(`/container/${id}/environment`, { env }); }; @@ -86,49 +91,21 @@ const getVersions = async (id: string, cache?: boolean) => { return data; }; -const containersRoutes = { - all: getAllContainers, - tags: getAllTags, - search: searchContainers, -}; - -const containerRoutes = (id: string) => { - return { - get: () => getContainer(id), - delete: () => deleteContainer(id), - start: () => startContainer(id), - stop: () => stopContainer(id), - patch: (params: any) => patchContainer(id, params), - logs: { - get: () => getLogs(id), - }, - env: { - save: (env: Env) => saveEnv(id, env), - }, - docker: { - get: () => getDocker(id), - recreate: () => recreateDocker(id), - }, - update: { - service: () => updateService(id), - }, - versions: { - get: (cache?: boolean) => getVersions(id, cache), - }, - }; -}; - -const servicesRoutes = { - all: getAllServices, -}; - -const serviceRoutes = (service_id: string) => ({ - install: () => installService(service_id), -}); - -export const vxContainersRoutes = { - containers: containersRoutes, - container: containerRoutes, - services: servicesRoutes, - service: serviceRoutes, +export const API = { + getContainer, + getAllContainers, + getAllTags, + searchContainers, + deleteContainer, + startContainer, + stopContainer, + patchContainer, + getLogs, + saveEnv, + getDockerInfo: getDocker, + recreateDocker, + updateService, + getVersions, + installService, + getAllServices, }; diff --git a/src/apps/Containers/backend/models.ts b/src/apps/Containers/backend/models.ts new file mode 100644 index 00000000..fb6a695f --- /dev/null +++ b/src/apps/Containers/backend/models.ts @@ -0,0 +1,70 @@ +export type ContainerQuery = { + features?: string[]; + tags?: string[]; +}; + +export type ContainerUpdate = { + current_version: string; + latest_version: string; +}; + +export type ServiceUpdate = { + available?: boolean; +}; + +export type Tags = Tag[]; +export type Tag = { + container_id: string; + tag: string; +}; + +export type EnvVariables = EnvVariable[]; +export type EnvVariable = { + container_id: string; + type: string; + name: string; + value: string; + default: string; + description: string; +}; + +export type Containers = Container[]; +export type Container = { + id: string; + service_id: string; + user_id: string; + image: string; + image_tag: string; + status: string; + launch_on_startup: boolean; + name: string; + description?: string; + color?: string; + icon?: string; + command?: string; + environment: EnvVariables; + capabilities: { + container_id: string; + name: string; + }; + ports: { + container_id: string; + in: string; + out: string; + }[]; + volumes: { + container_id: string; + in: string; + out: string; + }[]; + sysctls: { + container_id: string; + name: string; + value: string; + }[]; + tags: Tags; + + update?: ContainerUpdate; + service_update?: ServiceUpdate; + databases?: { [key: string]: string }; +}; diff --git a/src/models/service.ts b/src/apps/Containers/backend/service.ts similarity index 100% rename from src/models/service.ts rename to src/apps/Containers/backend/service.ts diff --git a/src/apps/Containers/components/EnvVariableInput/EnvVariableInput.tsx b/src/apps/Containers/components/EnvVariableInput/EnvVariableInput.tsx index 49b05927..5dc7ead6 100644 --- a/src/apps/Containers/components/EnvVariableInput/EnvVariableInput.tsx +++ b/src/apps/Containers/components/EnvVariableInput/EnvVariableInput.tsx @@ -1,6 +1,6 @@ import { TextField } from "@vertex-center/components"; import TimezoneField from "../../../../components/TimezoneField/TimezoneField"; -import { EnvVariable } from "../../../../models/service"; +import { EnvVariable } from "../../backend/models"; type Props = { id: string; @@ -16,7 +16,7 @@ export default function EnvVariableInput(props: Readonly) { const inputProps = { id, value, - label: env.display_name, + label: env.name, name: env.name, description: env.description, onChange: (e: any) => onChange(e.target.value), diff --git a/src/apps/Containers/components/SelectTags/SelectTags.tsx b/src/apps/Containers/components/SelectTags/SelectTags.tsx index 01dc2dd1..3da729e6 100644 --- a/src/apps/Containers/components/SelectTags/SelectTags.tsx +++ b/src/apps/Containers/components/SelectTags/SelectTags.tsx @@ -10,7 +10,7 @@ export default function SelectTags(props: Readonly) { const { selected } = props; const { tags, isLoading, isError } = useContainersTags(); - tags?.sort((a, b) => a.localeCompare(b)); + tags?.sort((a, b) => a.tag.localeCompare(b.tag)); const count = selected?.length; @@ -33,11 +33,11 @@ export default function SelectTags(props: Readonly) { > {tags?.map((tag) => ( - {tag} + {tag.tag} ))} diff --git a/src/apps/Containers/hooks/useContainer.tsx b/src/apps/Containers/hooks/useContainer.tsx index 8286f050..c0d0031c 100644 --- a/src/apps/Containers/hooks/useContainer.tsx +++ b/src/apps/Containers/hooks/useContainer.tsx @@ -1,26 +1,26 @@ -import { api } from "../../../backend/api/backend"; import { useQuery } from "@tanstack/react-query"; +import { API } from "../backend/api"; -export default function useContainer(uuid?: string) { +export default function useContainer(id?: string) { const queryContainer = useQuery({ - queryKey: ["containers", uuid], - queryFn: api.vxContainers.container(uuid).get, + queryKey: ["containers", id], + queryFn: () => API.getContainer(id), }); return { container: queryContainer.data, ...queryContainer }; } -export function useContainerLogs(uuid?: string) { +export function useContainerLogs(id?: string) { const queryLogs = useQuery({ - queryKey: ["container_logs", uuid], - queryFn: api.vxContainers.container(uuid).logs.get, + queryKey: ["container_logs", id], + queryFn: () => API.getLogs(id), }); return { logs: queryLogs.data, ...queryLogs }; } -export function useDockerInfo(uuid?: string) { +export function useDockerInfo(id?: string) { const queryDockerInfo = useQuery({ - queryKey: ["container_docker", uuid], - queryFn: api.vxContainers.container(uuid).docker.get, + queryKey: ["container_docker", id], + queryFn: () => API.getDockerInfo(id), }); return { dockerInfo: queryDockerInfo.data, ...queryDockerInfo }; } diff --git a/src/apps/Containers/hooks/useContainers.tsx b/src/apps/Containers/hooks/useContainers.tsx index d6a9a84f..7ec32f35 100644 --- a/src/apps/Containers/hooks/useContainers.tsx +++ b/src/apps/Containers/hooks/useContainers.tsx @@ -1,11 +1,11 @@ import { useQuery } from "@tanstack/react-query"; -import { api } from "../../../backend/api/backend"; -import { ContainerQuery } from "../../../models/container"; +import { API } from "../backend/api"; +import { ContainerQuery } from "../backend/models"; export function useContainersTags() { const queryTags = useQuery({ queryKey: ["containers", "tags"], - queryFn: api.vxContainers.containers.tags, + queryFn: API.getAllTags, }); const { data: tags } = queryTags; return { tags, ...queryTags }; @@ -14,7 +14,7 @@ export function useContainersTags() { export function useContainers(query: ContainerQuery) { const queryContainers = useQuery({ queryKey: ["containers", query], - queryFn: () => api.vxContainers.containers.search(query), + queryFn: () => API.searchContainers(query), }); const { data: containers } = queryContainers; return { containers, ...queryContainers }; diff --git a/src/apps/Containers/pages/Container/Container.tsx b/src/apps/Containers/pages/Container/Container.tsx index 6c4fd1ca..21009849 100644 --- a/src/apps/Containers/pages/Container/Container.tsx +++ b/src/apps/Containers/pages/Container/Container.tsx @@ -1,5 +1,4 @@ import { Fragment, useState } from "react"; -import { api } from "../../../../backend/api/backend"; import { Outlet, useNavigate, useOutlet, useParams } from "react-router-dom"; import styles from "./Container.module.sass"; import { Horizontal } from "../../../../components/Layouts/Layouts"; @@ -18,9 +17,10 @@ import { APIError } from "../../../../components/Error/APIError"; import { ProgressOverlay } from "../../../../components/Progress/Progress"; import { useServerEvent } from "../../../../hooks/useEvent"; import { useMutation, useQueryClient } from "@tanstack/react-query"; -import { Container as ContainerModel } from "../../../../models/container"; +import { Container as ContainerModel } from "../../backend/models"; import Container from "../../../../components/Container/Container"; import { useSidebar } from "../../../../hooks/useSidebar"; +import { API } from "../../backend/api"; export default function ContainerDetails() { const { uuid } = useParams(); @@ -50,18 +50,16 @@ export default function ContainerDetails() { const mutationContainerPower = useMutation({ mutationFn: async () => { if (container.status === "off" || container.status === "error") { - await api.vxContainers.container(uuid).start(); + await API.startContainer(uuid); } else { - await api.vxContainers.container(uuid).stop(); + await API.stopContainer(uuid); } }, }); const mutationDeleteContainer = useMutation({ - mutationFn: api.vxContainers.container(uuid).delete, - onSuccess: () => { - navigate("/app/containers"); - }, + mutationFn: () => API.deleteContainer(uuid), + onSuccess: () => navigate("/app/containers"), }); const { isLoading: isDeleting, @@ -89,13 +87,11 @@ export default function ContainerDetails() { icon={} link={l(`/app/containers/${uuid}/logs`)} /> - {container?.install_method === "docker" && ( - } - link={l(`/app/containers/${uuid}/docker`)} - /> - )} + } + link={l(`/app/containers/${uuid}/docker`)} + /> } link={l(`/app/containers/${uuid}/environment`)} /> - {container?.service?.databases && ( + {container?.databases && ( } @@ -160,15 +156,12 @@ export default function ContainerDetails() { - Are you sure you want to delete{" "} - {container?.display_name ?? container?.service?.name}? All - data will be permanently deleted. + Are you sure you want to delete {container?.name}? All data + will be permanently deleted. {isDeleting && } diff --git a/src/apps/Containers/pages/ContainerDatabase/ContainerDetailsDatabase.tsx b/src/apps/Containers/pages/ContainerDatabase/ContainerDetailsDatabase.tsx index 40bb37c5..432b5aab 100644 --- a/src/apps/Containers/pages/ContainerDatabase/ContainerDetailsDatabase.tsx +++ b/src/apps/Containers/pages/ContainerDatabase/ContainerDetailsDatabase.tsx @@ -16,7 +16,7 @@ import { Title, } from "@vertex-center/components"; import { api } from "../../../../backend/api/backend"; -import { DatabaseEnvironment } from "../../../../models/service"; +import { DatabaseEnvironment } from "../../backend/service"; import { APIError } from "../../../../components/Error/APIError"; import { ProgressOverlay } from "../../../../components/Progress/Progress"; import { useMutation, useQueryClient } from "@tanstack/react-query"; @@ -38,7 +38,7 @@ function Database(props: Readonly) { const [database, setDatabase] = useState(); const [error, setError] = useState(); - const env = database?.environment; + const env = database?.env; useEffect(() => { const uuid = container?.databases?.[dbID]; @@ -54,7 +54,7 @@ function Database(props: Readonly) { const onDatabaseChange = (container: Container) => { setDatabase(container); - onChange?.(dbID, container?.uuid); + onChange?.(dbID, container?.id); }; const port = env?.[database?.service?.features?.databases?.[0]?.port]; diff --git a/src/apps/Containers/pages/ContainerDocker/ContainerDocker.tsx b/src/apps/Containers/pages/ContainerDocker/ContainerDocker.tsx index 0f25f049..fd0654b9 100644 --- a/src/apps/Containers/pages/ContainerDocker/ContainerDocker.tsx +++ b/src/apps/Containers/pages/ContainerDocker/ContainerDocker.tsx @@ -7,7 +7,6 @@ import { Title, Vertical, } from "@vertex-center/components"; -import { api } from "../../../../backend/api/backend"; import { KeyValueGroup, KeyValueInfo, @@ -17,6 +16,7 @@ import { APIError } from "../../../../components/Error/APIError"; import { ProgressOverlay } from "../../../../components/Progress/Progress"; import { useDockerInfo } from "../../hooks/useContainer"; import Content from "../../../../components/Content/Content"; +import { API } from "../../backend/api"; export default function ContainerDocker() { const { uuid } = useParams(); @@ -30,9 +30,7 @@ export default function ContainerDocker() { setRecreatingContainer(true); setRecreatingContainerError(undefined); - api.vxContainers - .container(uuid) - .docker.recreate() + API.recreateDocker(uuid) .catch((err) => { setRecreatingContainerError( err?.response?.data?.message ?? err?.message diff --git a/src/apps/Containers/pages/ContainerEnv/ContainerEnv.tsx b/src/apps/Containers/pages/ContainerEnv/ContainerEnv.tsx index e93bd20f..23e69d99 100644 --- a/src/apps/Containers/pages/ContainerEnv/ContainerEnv.tsx +++ b/src/apps/Containers/pages/ContainerEnv/ContainerEnv.tsx @@ -1,40 +1,31 @@ -import { useEffect, useState } from "react"; +import { useState } from "react"; import { useParams } from "react-router-dom"; import EnvVariableInput from "../../components/EnvVariableInput/EnvVariableInput"; import { Button, MaterialIcon, Title } from "@vertex-center/components"; import { Horizontal } from "../../../../components/Layouts/Layouts"; import useContainer from "../../hooks/useContainer"; -import { Env, EnvVariable } from "../../../../models/service"; import styles from "./ContainerEnv.module.sass"; -import { api } from "../../../../backend/api/backend"; import { APIError } from "../../../../components/Error/APIError"; import { ProgressOverlay } from "../../../../components/Progress/Progress"; import { useMutation, useQueryClient } from "@tanstack/react-query"; import Content from "../../../../components/Content/Content"; +import { API } from "../../backend/api"; +import { EnvVariables } from "../../backend/models"; export default function ContainerEnv() { const { uuid } = useParams(); const queryClient = useQueryClient(); - const [env, setEnv] = useState< - { - env: EnvVariable; - value: any; - }[] - >(); - const { container, isLoading, error } = useContainer(uuid); // undefined = not saved AND never modified const [saved, setSaved] = useState(undefined); const mutationSaveEnv = useMutation({ - mutationFn: async (env: Env) => { - await api.vxContainers.container(uuid).env.save(env); - }, - onSuccess: () => { - setSaved(true); + mutationFn: async (env: EnvVariables) => { + await API.saveEnv(uuid, env); }, + onSuccess: () => setSaved(true), onSettled: () => { queryClient.invalidateQueries({ queryKey: ["containers", uuid], @@ -43,41 +34,20 @@ export default function ContainerEnv() { }); const { isLoading: isUploading } = mutationSaveEnv; - const save = () => { - const _env: Env = {}; - env.forEach((e) => { - _env[e.env.name] = e.value; - }); - mutationSaveEnv.mutate(_env); - }; - - useEffect(() => { - setEnv( - container?.service?.environment?.map((e) => ({ - env: e, - value: container?.environment[e.name] ?? e.default ?? "", - })) - ); - }, [container]); + const save = () => mutationSaveEnv.mutate(container?.environment ?? []); const onChange = (i: number, value: any) => { - setEnv((prev) => - prev.map((el, index) => { - if (index !== i) return el; - return { ...el, value }; - }) - ); setSaved(false); }; return ( Environment - {env?.map((env, i) => ( + {container?.environment?.map((env, i) => ( onChange(i, v)} disabled={isUploading} @@ -101,9 +71,7 @@ export default function ContainerEnv() { rightIcon={} disabled={isUploading || saved || saved === undefined} > - Save{" "} - {container?.install_method === "docker" && - "+ Recreate container"} + Save diff --git a/src/apps/Containers/pages/ContainerHome/ContainerHome.tsx b/src/apps/Containers/pages/ContainerHome/ContainerHome.tsx index 53560955..631c6ca9 100644 --- a/src/apps/Containers/pages/ContainerHome/ContainerHome.tsx +++ b/src/apps/Containers/pages/ContainerHome/ContainerHome.tsx @@ -1,59 +1,10 @@ -import { MaterialIcon, Title } from "@vertex-center/components"; -import styles from "./ContainerHome.module.sass"; -import { useParams } from "react-router-dom"; -import { Horizontal } from "../../../../components/Layouts/Layouts"; -import Spacer from "../../../../components/Spacer/Spacer"; -import classNames from "classnames"; -import useContainer from "../../hooks/useContainer"; -import { ProgressOverlay } from "../../../../components/Progress/Progress"; -import { APIError } from "../../../../components/Error/APIError"; +import { Title } from "@vertex-center/components"; import Content from "../../../../components/Content/Content"; export default function ContainerHome() { - const { uuid } = useParams(); - - const { container, isLoading, error } = useContainer(uuid); - return ( - URLs - - - + Home ); } diff --git a/src/apps/Containers/pages/ContainerSettings/ContainerSettings.tsx b/src/apps/Containers/pages/ContainerSettings/ContainerSettings.tsx index a9f6dc2c..3f859f4d 100644 --- a/src/apps/Containers/pages/ContainerSettings/ContainerSettings.tsx +++ b/src/apps/Containers/pages/ContainerSettings/ContainerSettings.tsx @@ -14,13 +14,13 @@ import { useParams } from "react-router-dom"; import useContainer from "../../hooks/useContainer"; import ToggleButton from "../../../../components/ToggleButton/ToggleButton"; import styles from "./ContainerSettings.module.sass"; -import { api } from "../../../../backend/api/backend"; import { APIError } from "../../../../components/Error/APIError"; import VersionTag from "../../../../components/VersionTag/VersionTag"; import classNames from "classnames"; import { ProgressOverlay } from "../../../../components/Progress/Progress"; import { useMutation, useQueryClient } from "@tanstack/react-query"; import Content from "../../../../components/Content/Content"; +import { API } from "../../backend/api"; export default function ContainerSettings() { const { uuid } = useParams(); @@ -40,17 +40,15 @@ export default function ContainerSettings() { useEffect(() => { if (!container) return; - setLaunchOnStartup(container?.launch_on_startup ?? true); - setDisplayName(container?.display_name ?? container?.service?.name); - setVersion(container?.version ?? "latest"); + setLaunchOnStartup(container.launch_on_startup); + setDisplayName(container.name); + setVersion(container?.image_tag ?? "latest"); reloadVersions(); }, [container]); const reloadVersions = (cache = true) => { setVersionsLoading(true); - api.vxContainers - .container(container.uuid) - .versions.get(cache) + API.getVersions(container.id, cache) .then((data) => { setVersions(data?.reverse()); }) @@ -62,7 +60,7 @@ export default function ContainerSettings() { const mutationSave = useMutation({ mutationFn: async () => { - await api.vxContainers.container(uuid).patch({ + await API.patchContainer(uuid, { launch_on_startup: launchOnStartup, display_name: displayName, version: version, diff --git a/src/apps/Containers/pages/ContainerUpdate/ContainerUpdate.tsx b/src/apps/Containers/pages/ContainerUpdate/ContainerUpdate.tsx index 0eda09a6..8c975b67 100644 --- a/src/apps/Containers/pages/ContainerUpdate/ContainerUpdate.tsx +++ b/src/apps/Containers/pages/ContainerUpdate/ContainerUpdate.tsx @@ -1,7 +1,6 @@ import { Caption } from "../../../../components/Text/Text"; import { useParams } from "react-router-dom"; import useContainer from "../../hooks/useContainer"; -import { api } from "../../../../backend/api/backend"; import { useState } from "react"; import { APIError } from "../../../../components/Error/APIError"; import { ProgressOverlay } from "../../../../components/Progress/Progress"; @@ -17,6 +16,7 @@ import { Title, } from "@vertex-center/components"; import Content from "../../../../components/Content/Content"; +import { API } from "../../backend/api"; export default function ContainerUpdate() { const { uuid } = useParams(); @@ -27,9 +27,7 @@ export default function ContainerUpdate() { const [error, setError] = useState(); const updateVertexIntegration = () => { - return api.vxContainers - .container(uuid) - .update.service() + return API.updateService(uuid) .then(() => { queryClient.invalidateQueries({ queryKey: ["containers", uuid], diff --git a/src/apps/Containers/pages/ContainersApp/ContainersApp.tsx b/src/apps/Containers/pages/ContainersApp/ContainersApp.tsx index 59d5cea4..a2b3c73b 100644 --- a/src/apps/Containers/pages/ContainersApp/ContainersApp.tsx +++ b/src/apps/Containers/pages/ContainersApp/ContainersApp.tsx @@ -2,7 +2,6 @@ import styles from "./ContainersApp.module.sass"; import Container, { Containers, } from "../../../../components/Container/Container"; -import { api } from "../../../../backend/api/backend"; import { APIError } from "../../../../components/Error/APIError"; import { ProgressOverlay } from "../../../../components/Progress/Progress"; import { useServerEvent } from "../../../../hooks/useEvent"; @@ -20,6 +19,7 @@ import { useState } from "react"; import NoItems from "../../../../components/NoItems/NoItems"; import { useContainers } from "../../hooks/useContainers"; import { useNavigate } from "react-router-dom"; +import { API } from "../../backend/api"; type ToolbarProps = { tags?: string[]; @@ -65,9 +65,9 @@ export default function ContainersApp() { containers[uuid].status === "off" || containers[uuid].status === "error" ) { - await api.vxContainers.container(uuid).start(); + await API.startContainer(uuid); } else { - await api.vxContainers.container(uuid).stop(); + await API.stopContainer(uuid); } }, }); @@ -106,18 +106,18 @@ export default function ContainersApp() { {!isLoading && !isError && ( - {Object.values(containers)?.map((inst) => ( + {containers?.map((c) => ( - mutationPower.mutate(inst.uuid), + mutationPower.mutate(c.id), }} /> ))} - {Object.values(containers)?.length === 0 && ( + {containers?.length === 0 && ( { - await api.vxContainers.service(serviceId).install(); - }, - onSettled: (data, error, serviceId) => { + mutationFn: API.installService, + onSettled: (data, error, serviceID) => { setDownloading( - downloading.filter(({ service: s }) => s.id !== serviceId) + downloading.filter(({ service: s }) => s.id !== serviceID) ); queryClient.invalidateQueries({ queryKey: ["containers"], @@ -86,21 +84,18 @@ export default function ContainersStore() { - {services?.map((service) => ( + {services?.map((serv) => ( openInstallPopup(service)} + key={serv.id} + service={serv} + onInstall={() => openInstallPopup(serv)} downloading={downloading.some( - ({ service: s }) => s.id === service.id + ({ service: s }) => s.id === serv.id )} installedCount={ - containers === undefined - ? undefined - : Object.values(containers)?.filter( - ({ service: s }) => - s.id === service.id - )?.length + containers?.filter( + (c) => c.service_id === serv.id + )?.length } /> ))} diff --git a/src/apps/Sql/Installer/SqlInstaller.tsx b/src/apps/Sql/Installer/SqlInstaller.tsx index ad62b93d..6cbdd411 100644 --- a/src/apps/Sql/Installer/SqlInstaller.tsx +++ b/src/apps/Sql/Installer/SqlInstaller.tsx @@ -1,7 +1,7 @@ import { api } from "../../../backend/api/backend"; import { ProgressOverlay } from "../../../components/Progress/Progress"; import Service from "../../../components/Service/Service"; -import { Service as ServiceModel } from "../../../models/service"; +import { Service as ServiceModel } from "../../Containers/backend/service"; import ServiceInstallPopup from "../../../components/ServiceInstallPopup/ServiceInstallPopup"; import { useState } from "react"; import { APIError } from "../../../components/Error/APIError"; diff --git a/src/apps/Sql/SqlDatabase/SqlDatabase.tsx b/src/apps/Sql/SqlDatabase/SqlDatabase.tsx index 3985a6b7..22ab29a4 100644 --- a/src/apps/Sql/SqlDatabase/SqlDatabase.tsx +++ b/src/apps/Sql/SqlDatabase/SqlDatabase.tsx @@ -51,10 +51,10 @@ export default function SqlDatabase() { return; } if (inst?.status === "off" || inst?.status === "error") { - await api.vxContainers.container(inst.uuid).start(); + await api.vxContainers.container(inst.id).start(); return; } - await api.vxContainers.container(inst.uuid).stop(); + await api.vxContainers.container(inst.id).stop(); }; const route = uuid ? `/container/${uuid}/events` : ""; @@ -97,9 +97,9 @@ export default function SqlDatabase() { onPower(container), }} /> diff --git a/src/backend/api/backend.ts b/src/backend/api/backend.ts index ba1189da..866a06df 100644 --- a/src/backend/api/backend.ts +++ b/src/backend/api/backend.ts @@ -1,5 +1,4 @@ import { About } from "../../models/about"; -import { vxContainersRoutes } from "./vxContainers"; import { vxTunnelsRoutes } from "./vxTunnels"; import { vxMonitoringRoutes } from "./vxMonitoring"; import { vxSqlRoutes } from "./vxSql"; @@ -19,7 +18,6 @@ const getAbout = async () => { export const api = { about: getAbout, - vxContainers: vxContainersRoutes, vxTunnels: vxTunnelsRoutes, vxMonitoring: vxMonitoringRoutes, vxSql: vxSqlRoutes, diff --git a/src/backend/api/vxServiceEditor.ts b/src/backend/api/vxServiceEditor.ts index 939e3974..912c0d1a 100644 --- a/src/backend/api/vxServiceEditor.ts +++ b/src/backend/api/vxServiceEditor.ts @@ -1,4 +1,4 @@ -import { Service } from "../../models/service"; +import { Service } from "../../apps/Containers/backend/service"; import { createServer } from "../server"; diff --git a/src/components/Container/Container.tsx b/src/components/Container/Container.tsx index 82d98562..fa77dfc5 100644 --- a/src/components/Container/Container.tsx +++ b/src/components/Container/Container.tsx @@ -4,7 +4,7 @@ import { Horizontal, Vertical } from "../Layouts/Layouts"; import { Link } from "react-router-dom"; import { Fragment, HTMLProps, MouseEventHandler } from "react"; import LoadingValue from "../LoadingValue/LoadingValue"; -import { Container as ContainerModel } from "../../models/container"; +import { Container as ContainerModel } from "../../apps/Containers/backend/models"; import LogoIcon from "../Logo/LogoIcon"; import { ContainerLed } from "../ContainerLed/ContainerLed"; import { v4 as uuidv4 } from "uuid"; @@ -35,10 +35,9 @@ type LCDProps = { function LCD(props: Readonly) { const { container } = props; - const { display_name, service, status } = container ?? {}; - const { name } = service ?? {}; + const { name, status } = container ?? {}; - let message; + let message = status; switch (status) { case "off": message = "Off"; @@ -64,16 +63,12 @@ function LCD(props: Readonly) { case "not-installed": message = "Not installed"; break; - default: - message = status; } let content = ( - - {display_name ?? name ?? } - + {name ?? }
) { ]; const inst = container.value; - const tag = tags?.find((t) => inst?.tags?.includes(t)); + const tag = tags?.find((name) => + inst?.tags?.includes((t) => t.tag === name) + ); // The uuidv4() is used to generate a unique key for containers that are not yet loaded. - const key = inst?.uuid ?? uuidv4(); + const key = inst?.id ?? uuidv4(); const content = ( diff --git a/src/components/ContainerInstaller/ContainerInstaller.tsx b/src/components/ContainerInstaller/ContainerInstaller.tsx index f0619f9b..b2393d38 100644 --- a/src/components/ContainerInstaller/ContainerInstaller.tsx +++ b/src/components/ContainerInstaller/ContainerInstaller.tsx @@ -2,11 +2,11 @@ import Container, { Containers } from "../Container/Container"; import { APIError } from "../Error/APIError"; import { Fragment, useEffect, useState } from "react"; import { ProgressOverlay } from "../Progress/Progress"; -import { Container as ContainerModel } from "../../models/container"; -import { api } from "../../backend/api/backend"; +import { Container as ContainerModel } from "../../apps/Containers/backend/models"; import { useServerEvent } from "../../hooks/useEvent"; import { useQueryClient } from "@tanstack/react-query"; import { useContainers } from "../../apps/Containers/hooks/useContainers"; +import { API } from "../../apps/Containers/backend/api"; type Props = { name: string; @@ -42,7 +42,7 @@ export default function ContainerInstaller(props: Readonly) { const inst = Object.values(containers ?? {})?.[0]; if (!inst) { setContainer({ - display_name: name, + name: name, status: "not-installed", }); return; @@ -67,19 +67,19 @@ export default function ContainerInstaller(props: Readonly) { }); }; - const onPower = async (inst: Inst) => { - if (!inst) { + const onPower = async (c: Inst) => { + if (!c) { console.error("Container not found"); return; } - if (inst?.status === "off" || inst?.status === "error") { - await api.vxContainers.container(inst.uuid).start(); + if (c?.status === "off" || c?.status === "error") { + await API.startContainer(c.id); return; } - await api.vxContainers.container(inst.uuid).stop(); + await API.stopContainer(c.id); }; - const route = container?.uuid ? `/container/${container?.uuid}/events` : ""; + const route = container?.id ? `/container/${container?.id}/events` : ""; // @ts-ignore useServerEvent(window.api_urls.containers, route, { @@ -94,8 +94,8 @@ export default function ContainerInstaller(props: Readonly) { onPower(container), diff --git a/src/components/Service/Service.tsx b/src/components/Service/Service.tsx index 42e6ef81..d19c5806 100644 --- a/src/components/Service/Service.tsx +++ b/src/components/Service/Service.tsx @@ -1,4 +1,4 @@ -import { Service as ServiceModel } from "../../models/service"; +import { Service as ServiceModel } from "../../apps/Containers/backend/service"; import styles from "./Service.module.sass"; import { Caption } from "../Text/Text"; diff --git a/src/components/ServiceInstallPopup/ServiceInstallPopup.tsx b/src/components/ServiceInstallPopup/ServiceInstallPopup.tsx index e1705f4b..ee34afad 100644 --- a/src/components/ServiceInstallPopup/ServiceInstallPopup.tsx +++ b/src/components/ServiceInstallPopup/ServiceInstallPopup.tsx @@ -1,7 +1,7 @@ import { APIError } from "../Error/APIError"; import { Button, MaterialIcon, Paragraph } from "@vertex-center/components"; import Popup from "../Popup/Popup"; -import { Service as ServiceModel } from "../../models/service"; +import { Service as ServiceModel } from "../../apps/Containers/backend/service"; import { Fragment, useState } from "react"; type Props = { diff --git a/src/components/ServiceLogo/ServiceLogo.tsx b/src/components/ServiceLogo/ServiceLogo.tsx index 0a33212c..7edb4756 100644 --- a/src/components/ServiceLogo/ServiceLogo.tsx +++ b/src/components/ServiceLogo/ServiceLogo.tsx @@ -1,4 +1,4 @@ -import { Service } from "../../models/service"; +import { Service } from "../../apps/Containers/backend/service"; import { MaterialIcon } from "@vertex-center/components"; type Props = { diff --git a/src/models/container.ts b/src/models/container.ts index c4213d41..e69de29b 100644 --- a/src/models/container.ts +++ b/src/models/container.ts @@ -1,41 +0,0 @@ -import { Service } from "./service"; - -export type InstallMethod = "script" | "release" | "docker"; - -export type ContainerQuery = { - features?: string[]; - tags?: string[]; -}; - -export type ContainerUpdate = { - current_version: string; - latest_version: string; -}; - -export type Operation = { - op: string; - from?: string; - path: string; - value?: string; -}; - -export type ServiceUpdate = { - available?: boolean; -}; - -export type Container = { - service: Service; - uuid: string; - status: string; - environment: { [key: string]: string }; - install_method?: InstallMethod; - launch_on_startup?: boolean; - display_name?: string; - databases?: { [key: string]: string }; - version?: string; - update?: ContainerUpdate; - service_update?: ServiceUpdate; - tags?: string[]; -}; - -export type Containers = { [uuid: string]: Container }; From f9691808e6915c41bc6b5c20b5d85ab337389206 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Quentin=20Guid=C3=A9e?= Date: Thu, 14 Dec 2023 10:48:47 -0500 Subject: [PATCH 2/6] Change the tags route MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Quentin Guidée --- src/apps/Containers/backend/api.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/apps/Containers/backend/api.ts b/src/apps/Containers/backend/api.ts index 7d4b8c8c..09b5a2e2 100644 --- a/src/apps/Containers/backend/api.ts +++ b/src/apps/Containers/backend/api.ts @@ -18,7 +18,7 @@ const getAllContainers = async () => { }; const getAllTags = async () => { - const { data } = await server.get(`/containers/tags`); + const { data } = await server.get(`/tags`); return data; }; From 076a3e1a50913adf6a5845e5e1501054346a27c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Quentin=20Guid=C3=A9e?= Date: Fri, 15 Dec 2023 06:05:40 -0500 Subject: [PATCH 3/6] containers: Fix env and settings with the new API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Quentin Guidée --- src/apps/Containers/backend/api.ts | 10 +++- src/apps/Containers/backend/models.ts | 2 + .../EnvVariableInput/EnvVariableInput.tsx | 2 +- src/apps/Containers/hooks/useContainer.tsx | 12 +++++ .../pages/ContainerEnv/ContainerEnv.tsx | 23 ++++++--- .../ContainerSettings/ContainerSettings.tsx | 48 +++++++++---------- 6 files changed, 64 insertions(+), 33 deletions(-) diff --git a/src/apps/Containers/backend/api.ts b/src/apps/Containers/backend/api.ts index 09b5a2e2..29e54e0a 100644 --- a/src/apps/Containers/backend/api.ts +++ b/src/apps/Containers/backend/api.ts @@ -65,6 +65,13 @@ const getLogs = async (id: string) => { return data; }; +const getContainerEnvironment = async (id: string) => { + const { data } = await server.get( + `/container/${id}/environment` + ); + return data; +}; + const saveEnv = (id: string, env: EnvVariables) => { return server.patch(`/container/${id}/environment`, { env }); }; @@ -86,7 +93,7 @@ const updateService = (id: string) => { const getVersions = async (id: string, cache?: boolean) => { const { data } = await server.get( - `/container/${id}/versions?reload=${!cache}` + `/container/${id}/versions?cache=${cache}` ); return data; }; @@ -101,6 +108,7 @@ export const API = { stopContainer, patchContainer, getLogs, + getContainerEnvironment, saveEnv, getDockerInfo: getDocker, recreateDocker, diff --git a/src/apps/Containers/backend/models.ts b/src/apps/Containers/backend/models.ts index fb6a695f..91f1dc71 100644 --- a/src/apps/Containers/backend/models.ts +++ b/src/apps/Containers/backend/models.ts @@ -23,9 +23,11 @@ export type EnvVariable = { container_id: string; type: string; name: string; + display_name: string; value: string; default: string; description: string; + secret: boolean; }; export type Containers = Container[]; diff --git a/src/apps/Containers/components/EnvVariableInput/EnvVariableInput.tsx b/src/apps/Containers/components/EnvVariableInput/EnvVariableInput.tsx index 5dc7ead6..aafce036 100644 --- a/src/apps/Containers/components/EnvVariableInput/EnvVariableInput.tsx +++ b/src/apps/Containers/components/EnvVariableInput/EnvVariableInput.tsx @@ -16,7 +16,7 @@ export default function EnvVariableInput(props: Readonly) { const inputProps = { id, value, - label: env.name, + label: env.display_name, name: env.name, description: env.description, onChange: (e: any) => onChange(e.target.value), diff --git a/src/apps/Containers/hooks/useContainer.tsx b/src/apps/Containers/hooks/useContainer.tsx index c0d0031c..3cc02e14 100644 --- a/src/apps/Containers/hooks/useContainer.tsx +++ b/src/apps/Containers/hooks/useContainer.tsx @@ -24,3 +24,15 @@ export function useDockerInfo(id?: string) { }); return { dockerInfo: queryDockerInfo.data, ...queryDockerInfo }; } + +export function useContainerEnv(id?: string) { + const queryEnv = useQuery({ + queryKey: ["container_env", id], + queryFn: () => API.getContainerEnvironment(id), + }); + return { + env: queryEnv.data, + isLoadingEnv: queryEnv.isLoading, + errorEnv: queryEnv.error, + }; +} diff --git a/src/apps/Containers/pages/ContainerEnv/ContainerEnv.tsx b/src/apps/Containers/pages/ContainerEnv/ContainerEnv.tsx index 23e69d99..942ab6ce 100644 --- a/src/apps/Containers/pages/ContainerEnv/ContainerEnv.tsx +++ b/src/apps/Containers/pages/ContainerEnv/ContainerEnv.tsx @@ -1,9 +1,9 @@ -import { useState } from "react"; +import { useEffect, useState } from "react"; import { useParams } from "react-router-dom"; import EnvVariableInput from "../../components/EnvVariableInput/EnvVariableInput"; import { Button, MaterialIcon, Title } from "@vertex-center/components"; import { Horizontal } from "../../../../components/Layouts/Layouts"; -import useContainer from "../../hooks/useContainer"; +import { useContainerEnv } from "../../hooks/useContainer"; import styles from "./ContainerEnv.module.sass"; import { APIError } from "../../../../components/Error/APIError"; import { ProgressOverlay } from "../../../../components/Progress/Progress"; @@ -16,7 +16,13 @@ export default function ContainerEnv() { const { uuid } = useParams(); const queryClient = useQueryClient(); - const { container, isLoading, error } = useContainer(uuid); + const { env: currentEnv, isLoadingEnv, errorEnv } = useContainerEnv(uuid); + const [env, setEnv] = useState(currentEnv); + + useEffect(() => { + setEnv(currentEnv); + setSaved(undefined); + }, [currentEnv]); // undefined = not saved AND never modified const [saved, setSaved] = useState(undefined); @@ -34,16 +40,19 @@ export default function ContainerEnv() { }); const { isLoading: isUploading } = mutationSaveEnv; - const save = () => mutationSaveEnv.mutate(container?.environment ?? []); + const save = () => mutationSaveEnv.mutate(env ?? []); const onChange = (i: number, value: any) => { + const newEnv = [...env]; + newEnv[i].value = value; + setEnv(newEnv); setSaved(false); }; return ( Environment - {container?.environment?.map((env, i) => ( + {env?.map((env, i) => ( ))} - + {saved && ( - + ); } diff --git a/src/apps/Containers/pages/ContainerSettings/ContainerSettings.tsx b/src/apps/Containers/pages/ContainerSettings/ContainerSettings.tsx index 3f859f4d..8ced9146 100644 --- a/src/apps/Containers/pages/ContainerSettings/ContainerSettings.tsx +++ b/src/apps/Containers/pages/ContainerSettings/ContainerSettings.tsx @@ -28,11 +28,11 @@ export default function ContainerSettings() { const { container, isLoading: isLoadingContainer } = useContainer(uuid); - const [displayName, setDisplayName] = useState(); + const [name, setName] = useState(); const [launchOnStartup, setLaunchOnStartup] = useState(); - const [version, setVersion] = useState(); - const [versions, setVersions] = useState(); - const [versionsLoading, setVersionsLoading] = useState(false); + const [imageTag, setImageTag] = useState(); + const [imageTags, setImageTags] = useState(); + const [imageTagsLoading, setImageTagsLoading] = useState(false); // undefined = not saved AND never modified const [saved, setSaved] = useState(undefined); @@ -41,20 +41,20 @@ export default function ContainerSettings() { useEffect(() => { if (!container) return; setLaunchOnStartup(container.launch_on_startup); - setDisplayName(container.name); - setVersion(container?.image_tag ?? "latest"); + setName(container.name); + setImageTag(container?.image_tag ?? "latest"); reloadVersions(); }, [container]); const reloadVersions = (cache = true) => { - setVersionsLoading(true); + setImageTagsLoading(true); API.getVersions(container.id, cache) .then((data) => { - setVersions(data?.reverse()); + setImageTags(data?.reverse()); }) .catch(setError) .finally(() => { - setVersionsLoading(false); + setImageTagsLoading(false); }); }; @@ -62,8 +62,8 @@ export default function ContainerSettings() { mutationFn: async () => { await API.patchContainer(uuid, { launch_on_startup: launchOnStartup, - display_name: displayName, - version: version, + name, + imageTag, }); }, onSuccess: () => { @@ -78,20 +78,20 @@ export default function ContainerSettings() { const { isLoading: isUploading } = mutationSave; const onVersionChange = (v: any) => { - setVersion(v); + setImageTag(v); setSaved(false); }; const versionValue = (
- {version === "latest" ? ( - "Always pull latest version" + {imageTag === "latest" ? ( + "Always pull latest" ) : ( - {version} + {imageTag} )}
); @@ -100,7 +100,7 @@ export default function ContainerSettings() { Settings @@ -119,9 +119,9 @@ export default function ContainerSettings() { id="container-name" label="Container name" description="The custom name of your choice for this service" - value={displayName} + value={name} onChange={(e: any) => { - setDisplayName(e.target.value); + setName(e.target.value); setSaved(false); }} disabled={isLoadingContainer} @@ -131,16 +131,16 @@ export default function ContainerSettings() { id="container-version" label="Version" onChange={onVersionChange} - disabled={isLoadingContainer || versionsLoading} + disabled={isLoadingContainer || imageTagsLoading} // @ts-ignore value={versionValue} > - {versions?.includes("latest") && ( + {imageTags?.includes("latest") && ( - Always pull latest version + Always pull latest )} - {versions?.map((v) => { + {imageTags?.map((v) => { if (v === "latest") { return null; } @@ -154,7 +154,7 @@ export default function ContainerSettings() { From 399596830b233c5533279de80bcd5817e35636f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Quentin=20Guid=C3=A9e?= Date: Fri, 15 Dec 2023 08:57:53 -0500 Subject: [PATCH 4/6] sql: Use the new API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Quentin Guidée --- src/apps/Sql/Installer/SqlInstaller.tsx | 24 ++++++++++++------------ src/apps/Sql/SqlApp/SqlApp.tsx | 14 +++++++------- src/apps/Sql/SqlDatabase/SqlDatabase.tsx | 13 ++++++------- 3 files changed, 25 insertions(+), 26 deletions(-) diff --git a/src/apps/Sql/Installer/SqlInstaller.tsx b/src/apps/Sql/Installer/SqlInstaller.tsx index 6cbdd411..1bf5b4f2 100644 --- a/src/apps/Sql/Installer/SqlInstaller.tsx +++ b/src/apps/Sql/Installer/SqlInstaller.tsx @@ -8,13 +8,15 @@ import { APIError } from "../../../components/Error/APIError"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { List, Title } from "@vertex-center/components"; import Content from "../../../components/Content/Content"; +import { API } from "../../Containers/backend/api"; +import { useContainers } from "../../Containers/hooks/useContainers"; export default function SqlInstaller() { const queryClient = useQueryClient(); const queryServices = useQuery({ queryKey: ["services"], - queryFn: api.vxContainers.services.all, + queryFn: API.getAllServices, }); const { data: services, @@ -22,15 +24,11 @@ export default function SqlInstaller() { error: servicesError, } = queryServices; - const queryContainers = useQuery({ - queryKey: ["containers"], - queryFn: api.vxContainers.containers.all, - }); const { - data: containers, - isLoading: isContainersLoading, + containers, + isLoading: isLoadingContainers, error: containersError, - } = queryContainers; + } = useContainers({}); const [selectedService, setSelectedService] = useState(); const [showPopup, setShowPopup] = useState(false); @@ -77,7 +75,7 @@ export default function SqlInstaller() { return ( - + Installer @@ -100,9 +98,11 @@ export default function SqlInstaller() { installedCount={ containers === undefined ? undefined - : Object.values(containers)?.filter( - ({ service: s }) => - s.id === service.id + : Object.values( + containers ?? [] + )?.filter( + ({ service_id }) => + service_id === service.id )?.length } /> diff --git a/src/apps/Sql/SqlApp/SqlApp.tsx b/src/apps/Sql/SqlApp/SqlApp.tsx index 41ebc467..271e9f04 100644 --- a/src/apps/Sql/SqlApp/SqlApp.tsx +++ b/src/apps/Sql/SqlApp/SqlApp.tsx @@ -22,9 +22,9 @@ export default function SqlApp() { {Object.values(containers ?? {}).length > 0 && ( - {Object.values(containers ?? {})?.map((inst) => { + {Object.values(containers ?? {})?.map((c) => { let icon = ; - const type = inst?.service?.features?.databases?.find( + const type = c?.service?.features?.databases?.find( (d) => d.category === "sql" )?.type; if (type === "postgres") { @@ -33,15 +33,15 @@ export default function SqlApp() { return ( ) } diff --git a/src/apps/Sql/SqlDatabase/SqlDatabase.tsx b/src/apps/Sql/SqlDatabase/SqlDatabase.tsx index 22ab29a4..95dde36c 100644 --- a/src/apps/Sql/SqlDatabase/SqlDatabase.tsx +++ b/src/apps/Sql/SqlDatabase/SqlDatabase.tsx @@ -22,19 +22,18 @@ import { import { useQuery, useQueryClient } from "@tanstack/react-query"; import NoItems from "../../../components/NoItems/NoItems"; import Content from "../../../components/Content/Content"; +import useContainer from "../../Containers/hooks/useContainer"; +import { API } from "../../Containers/backend/api"; export default function SqlDatabase() { const { uuid } = useParams(); const queryClient = useQueryClient(); const { - data: container, + container, isLoading: isLoadingContainer, error: errorContainer, - } = useQuery({ - queryKey: ["containers", uuid], - queryFn: api.vxContainers.container(uuid).get, - }); + } = useContainer(uuid); const { data: db, @@ -51,10 +50,10 @@ export default function SqlDatabase() { return; } if (inst?.status === "off" || inst?.status === "error") { - await api.vxContainers.container(inst.id).start(); + await API.startContainer(inst.id); return; } - await api.vxContainers.container(inst.id).stop(); + await API.stopContainer(inst.id); }; const route = uuid ? `/container/${uuid}/events` : ""; From 78663869c62f06bbb2f346b5b23da4ca56dc55b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Quentin=20Guid=C3=A9e?= Date: Sat, 16 Dec 2023 13:51:06 -0500 Subject: [PATCH 5/6] containers: Fix unaffected imageTag change MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Quentin Guidée --- .../Containers/pages/ContainerSettings/ContainerSettings.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/apps/Containers/pages/ContainerSettings/ContainerSettings.tsx b/src/apps/Containers/pages/ContainerSettings/ContainerSettings.tsx index 8ced9146..a558d165 100644 --- a/src/apps/Containers/pages/ContainerSettings/ContainerSettings.tsx +++ b/src/apps/Containers/pages/ContainerSettings/ContainerSettings.tsx @@ -62,8 +62,8 @@ export default function ContainerSettings() { mutationFn: async () => { await API.patchContainer(uuid, { launch_on_startup: launchOnStartup, - name, - imageTag, + name: name, + image_tag: imageTag, }); }, onSuccess: () => { From c369dd3a427e16079e017f0426cf6fd07cc82116 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Quentin=20Guid=C3=A9e?= Date: Sat, 16 Dec 2023 14:42:35 -0500 Subject: [PATCH 6/6] containers: Merge get all containers and containers search MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Quentin Guidée --- src/apps/Containers/backend/api.ts | 18 +++++-------- src/apps/Containers/backend/models.ts | 2 +- .../ContainerSelect/ContainerSelect.tsx | 25 ++++++++----------- src/apps/Containers/hooks/useContainers.tsx | 6 ++--- .../ContainerDetailsDatabase.tsx | 2 +- .../pages/ContainersStore/ContainersStore.tsx | 2 +- src/apps/Sql/SqlDatabase/SqlDatabase.tsx | 2 +- src/models/container.ts | 0 8 files changed, 24 insertions(+), 33 deletions(-) delete mode 100644 src/models/container.ts diff --git a/src/apps/Containers/backend/api.ts b/src/apps/Containers/backend/api.ts index 29e54e0a..df4b1496 100644 --- a/src/apps/Containers/backend/api.ts +++ b/src/apps/Containers/backend/api.ts @@ -1,7 +1,7 @@ import { createServer } from "../../../backend/server"; import { Container, - ContainerQuery, + ContainerFilters, Containers, EnvVariables, Tags, @@ -12,8 +12,10 @@ import { Service } from "./service"; // @ts-ignore const server = createServer(window.api_urls.containers); -const getAllContainers = async () => { - const { data } = await server.get(`/containers`); +const getContainers = async (query?: ContainerFilters) => { + const { data } = await server.get(`/containers`, { + params: query, + }); return data; }; @@ -22,13 +24,6 @@ const getAllTags = async () => { return data; }; -const searchContainers = async (query: ContainerQuery) => { - const { data } = await server.get(`/containers/search`, { - params: query, - }); - return data; -}; - const installService = async (serviceId: string) => { const { data } = await server.post(`/service/${serviceId}/install`); return data; @@ -100,9 +95,8 @@ const getVersions = async (id: string, cache?: boolean) => { export const API = { getContainer, - getAllContainers, + getContainers, getAllTags, - searchContainers, deleteContainer, startContainer, stopContainer, diff --git a/src/apps/Containers/backend/models.ts b/src/apps/Containers/backend/models.ts index 91f1dc71..7e2d3cb0 100644 --- a/src/apps/Containers/backend/models.ts +++ b/src/apps/Containers/backend/models.ts @@ -1,4 +1,4 @@ -export type ContainerQuery = { +export type ContainerFilters = { features?: string[]; tags?: string[]; }; diff --git a/src/apps/Containers/components/ContainerSelect/ContainerSelect.tsx b/src/apps/Containers/components/ContainerSelect/ContainerSelect.tsx index 07e53037..b5a68966 100644 --- a/src/apps/Containers/components/ContainerSelect/ContainerSelect.tsx +++ b/src/apps/Containers/components/ContainerSelect/ContainerSelect.tsx @@ -1,25 +1,24 @@ import { SelectField, SelectOption } from "@vertex-center/components"; -import { Container, ContainerQuery } from "../../../../models/container"; -import { api } from "../../../../backend/api/backend"; import Progress from "../../../../components/Progress"; import ServiceLogo from "../../../../components/ServiceLogo/ServiceLogo"; import { useQuery } from "@tanstack/react-query"; import { APIError } from "../../../../components/Error/APIError"; import { Fragment } from "react"; +import { API } from "../../backend/api"; +import { Container, ContainerFilters } from "../../backend/models"; type Props = { container?: Container; onChange?: (container?: Container) => void; - - query?: ContainerQuery; + filters?: ContainerFilters; }; export default function ContainerSelect(props: Readonly) { - const { container, onChange, query } = props; + const { container, onChange, filters } = props; const queryContainers = useQuery({ - queryKey: ["containers", query], - queryFn: () => api.vxContainers.containers.search(query), + queryKey: ["containers", filters], + queryFn: () => API.getContainers(filters), }); const { data: containers, isLoading, error } = queryContainers; @@ -39,9 +38,7 @@ export default function ContainerSelect(props: Readonly) { const value = ( {container && } - {container?.display_name ?? - container?.service?.name ?? - "Select an container"} + {container?.name ?? "Select an container"} ); @@ -49,10 +46,10 @@ export default function ContainerSelect(props: Readonly) { // @ts-ignore None - {Object.entries(containers ?? [])?.map(([, container]) => ( - - - {container?.display_name ?? container?.service?.name} + {Object.entries(containers ?? [])?.map(([, c]) => ( + + + {c?.name} ))} diff --git a/src/apps/Containers/hooks/useContainers.tsx b/src/apps/Containers/hooks/useContainers.tsx index 7ec32f35..8be0a1a6 100644 --- a/src/apps/Containers/hooks/useContainers.tsx +++ b/src/apps/Containers/hooks/useContainers.tsx @@ -1,6 +1,6 @@ import { useQuery } from "@tanstack/react-query"; import { API } from "../backend/api"; -import { ContainerQuery } from "../backend/models"; +import { ContainerFilters } from "../backend/models"; export function useContainersTags() { const queryTags = useQuery({ @@ -11,10 +11,10 @@ export function useContainersTags() { return { tags, ...queryTags }; } -export function useContainers(query: ContainerQuery) { +export function useContainers(query: ContainerFilters) { const queryContainers = useQuery({ queryKey: ["containers", query], - queryFn: () => API.searchContainers(query), + queryFn: () => API.getContainers(query), }); const { data: containers } = queryContainers; return { containers, ...queryContainers }; diff --git a/src/apps/Containers/pages/ContainerDatabase/ContainerDetailsDatabase.tsx b/src/apps/Containers/pages/ContainerDatabase/ContainerDetailsDatabase.tsx index 432b5aab..124a6b6d 100644 --- a/src/apps/Containers/pages/ContainerDatabase/ContainerDetailsDatabase.tsx +++ b/src/apps/Containers/pages/ContainerDatabase/ContainerDetailsDatabase.tsx @@ -72,7 +72,7 @@ function Database(props: Readonly) { diff --git a/src/apps/Containers/pages/ContainersStore/ContainersStore.tsx b/src/apps/Containers/pages/ContainersStore/ContainersStore.tsx index 275e63d9..bc97f361 100644 --- a/src/apps/Containers/pages/ContainersStore/ContainersStore.tsx +++ b/src/apps/Containers/pages/ContainersStore/ContainersStore.tsx @@ -31,7 +31,7 @@ export default function ContainersStore() { const queryContainers = useQuery({ queryKey: ["containers"], - queryFn: API.getAllContainers, + queryFn: API.getContainers, }); const { data: containers, diff --git a/src/apps/Sql/SqlDatabase/SqlDatabase.tsx b/src/apps/Sql/SqlDatabase/SqlDatabase.tsx index 95dde36c..0b86b89a 100644 --- a/src/apps/Sql/SqlDatabase/SqlDatabase.tsx +++ b/src/apps/Sql/SqlDatabase/SqlDatabase.tsx @@ -1,6 +1,6 @@ import { useParams } from "react-router-dom"; import { api } from "../../../backend/api/backend"; -import { Container as ContainerModel } from "../../../models/container"; +import { Container as ContainerModel } from "../../../apps/Containers/backend/models"; import Container, { Containers } from "../../../components/Container/Container"; import { v4 as uuidv4 } from "uuid"; import { useServerEvent } from "../../../hooks/useEvent"; diff --git a/src/models/container.ts b/src/models/container.ts deleted file mode 100644 index e69de29b..00000000