Skip to content
This repository has been archived by the owner on Mar 3, 2024. It is now read-only.

Commit

Permalink
apps/containers: Install container from name
Browse files Browse the repository at this point in the history
Signed-off-by: Quentin Guidée <[email protected]>
  • Loading branch information
quentinguidee committed Jan 21, 2024
1 parent a3520c8 commit 68d5024
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 29 deletions.
9 changes: 7 additions & 2 deletions src/apps/Containers/backend/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,13 @@ const getContainer = async (id: string) => {
return data;
};

const createContainer = async (template_id: string) => {
const { data } = await server.post(`/containers`, { template_id });
export type CreateContainerOptions = {
template_id?: string;
image?: string;
};

const createContainer = async (options: CreateContainerOptions) => {
const { data } = await server.post(`/containers`, options);
return data;
};

Expand Down
28 changes: 28 additions & 0 deletions src/apps/Containers/hooks/useCreateContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import {
useMutation,
UseMutationOptions,
useQueryClient,
} from "@tanstack/react-query";
import { API, CreateContainerOptions } from "../backend/api";

export const useCreateContainer = (
options: UseMutationOptions<unknown, unknown, CreateContainerOptions>
) => {
const { onSuccess, ...others } = options;
const queryClient = useQueryClient();
const mutation = useMutation({
mutationKey: ["containers_create"],
mutationFn: API.createContainer,
onSuccess: (...args) => {
queryClient.invalidateQueries(["containers"]);
options.onSuccess?.(...args);
},
...others,
});
const {
mutate: createContainer,
isLoading: isCreatingContainer,
error: errorCreatingContainer,
} = mutation;
return { createContainer, isCreatingContainer, errorCreatingContainer };
};
52 changes: 28 additions & 24 deletions src/apps/Containers/pages/ContainersStore/ContainersStore.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Service from "../../../../components/Service/Service";
import { APIError } from "../../../../components/Error/APIError";
import { ProgressOverlay } from "../../../../components/Progress/Progress";
import ServiceInstallPopup from "../../../../components/ServiceInstallPopup/ServiceInstallPopup";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import {
List,
ListActions,
Expand All @@ -23,6 +23,7 @@ import { API } from "../../backend/api";
import Content from "../../../../components/Content/Content";
import { SiDocker } from "@icons-pack/react-simple-icons";
import ManualInstallPopup from "./ManualInstallPopup";
import { useCreateContainer } from "../../hooks/useCreateContainer";

type Downloading = {
service: ServiceModel;
Expand Down Expand Up @@ -53,40 +54,39 @@ export default function ContainersStore() {
error: containersError,
} = queryContainers;

const mutationCreateContainer = useMutation({
mutationFn: API.createContainer,
onSettled: (data, error, templateID) => {
setDownloading(
downloading.filter(({ service: s }) => s.id !== templateID)
);
queryClient.invalidateQueries({
queryKey: ["containers"],
});
},
});
const { isLoading: isInstalling, error: installError } =
mutationCreateContainer;
const { createContainer, isCreatingContainer, errorCreatingContainer } =
useCreateContainer({
onSettled: (data, error, options) => {
setDownloading(
downloading.filter(
({ service: s }) => s.id !== options.template_id
)
);
},
});

const install = () => {
const service = selectedService;
setDownloading((prev) => [...prev, { service }]);
const template = selectedTemplate;
setDownloading((prev) => [...prev, { service: template }]);
setShowInstallPopup(false);
mutationCreateContainer.mutate(service.id);
createContainer({
template_id: template.id,
});
};

const [showInstallPopup, setShowInstallPopup] = useState<boolean>(false);
const [showManualInstallPopup, setShowManualInstallPopup] =
useState<boolean>(false);
const [selectedService, setSelectedService] = useState<ServiceModel>();
const [selectedTemplate, setSelectedTemplate] = useState<ServiceModel>();
const [downloading, setDownloading] = useState<Downloading[]>([]);

const openInstallPopup = (service: ServiceModel) => {
setSelectedService(service);
const openInstallPopup = (template: ServiceModel) => {
setSelectedTemplate(template);
setShowInstallPopup(true);
};

const closeInstallPopup = () => {
setSelectedService(undefined);
setSelectedTemplate(undefined);
setShowInstallPopup(false);
};

Expand All @@ -98,12 +98,16 @@ export default function ContainersStore() {
setShowManualInstallPopup(false);
};

const error = servicesError ?? containersError ?? installError;
const error = servicesError ?? containersError ?? errorCreatingContainer;

return (
<Content>
<ProgressOverlay
show={isContainersLoading ?? isServicesLoading ?? isInstalling}
show={
isContainersLoading ??
isServicesLoading ??
isCreatingContainer
}
/>
<Vertical gap={30} className={styles.content}>
<List>
Expand Down Expand Up @@ -145,7 +149,7 @@ export default function ContainersStore() {
</List>
</Vertical>
<ServiceInstallPopup
service={selectedService}
service={selectedTemplate}
show={showInstallPopup}
dismiss={closeInstallPopup}
install={install}
Expand Down
30 changes: 27 additions & 3 deletions src/apps/Containers/pages/ContainersStore/ManualInstallPopup.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import Popup from "../../../../components/Popup/Popup";
import { Button, Input, MaterialIcon } from "@vertex-center/components";
import { Fragment } from "react";
import { ChangeEvent, Fragment, useState } from "react";
import { APIError } from "../../../../components/Error/APIError";
import { useCreateContainer } from "../../hooks/useCreateContainer";
import { ProgressOverlay } from "../../../../components/Progress/Progress";

type Props = {
show: boolean;
Expand All @@ -10,14 +13,25 @@ type Props = {
export default function ManualInstallPopup(props: Readonly<Props>) {
const { show, dismiss } = props;

const [image, setImage] = useState<string>();

const { createContainer, isCreatingContainer, errorCreatingContainer } =
useCreateContainer({});

const create = () => createContainer({ image });

const onImageChange = (e: ChangeEvent<HTMLInputElement>) => {
setImage(e.target.value);
};

const actions = (
<Fragment>
<Button variant="outlined" onClick={dismiss}>
Cancel
</Button>
<Button
variant="colored"
onClick={dismiss}
onClick={create}
rightIcon={<MaterialIcon icon="download" />}
>
Install
Expand All @@ -32,7 +46,17 @@ export default function ManualInstallPopup(props: Readonly<Props>) {
title="Install from Docker Registry"
actions={actions}
>
<Input id="image" label="Image" placeholder="postgres" required />
<Input
id="image"
label="Image"
placeholder="postgres"
value={image}
onChange={onImageChange}
disabled={isCreatingContainer}
required
/>
<ProgressOverlay show={isCreatingContainer} />
<APIError error={errorCreatingContainer} />
</Popup>
);
}

0 comments on commit 68d5024

Please sign in to comment.