feat: add Deployment Jobs, Template Categories, Virtual Machine details and management pages
- Implemented DeploymentJobsPage for managing deployment jobs with filtering and retry functionality. - Created TemplateCategoriesPage for managing template categories with add, edit, and delete capabilities. - Developed VirtualMachineDetailsPage to display detailed information about a specific virtual machine. - Added VirtualMachinesPage for listing, adding, editing, and deleting virtual machines, including linking and unlinking to domains.
This commit is contained in:
@@ -1,79 +1,191 @@
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import {
|
||||
Button,
|
||||
Checkbox,
|
||||
Combobox,
|
||||
Field,
|
||||
Input,
|
||||
makeStyles,
|
||||
Option,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHeader,
|
||||
TableHeaderCell,
|
||||
TableRow,
|
||||
Tooltip,
|
||||
} from "@fluentui/react-components";
|
||||
import { OpenRegular } from "@fluentui/react-icons";
|
||||
import { useState } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { portalApi } from "../api/portalApi";
|
||||
import { DataState } from "../components/DataState";
|
||||
import { FormActions, FormGrid, FormSection } from "../components/FormSection";
|
||||
import { PageHeader } from "../components/PageHeader";
|
||||
|
||||
const useStyles = makeStyles({
|
||||
actions: {
|
||||
display: "flex",
|
||||
gap: "6px",
|
||||
},
|
||||
});
|
||||
|
||||
export function DeploymentGroupsPage() {
|
||||
const styles = useStyles();
|
||||
const queryClient = useQueryClient();
|
||||
const [serviceId, setServiceId] = useState("");
|
||||
const [templateId, setTemplateId] = useState("");
|
||||
const [virtualMachineIds, setVirtualMachineIds] = useState<string[]>([]);
|
||||
const [status, setStatus] = useState("New");
|
||||
const { data, error, isLoading } = useQuery({
|
||||
queryKey: ["deploymentGroups"],
|
||||
queryFn: ({ signal }) => portalApi.getDeploymentGroups(signal),
|
||||
queryKey: ["deployment-batches"],
|
||||
queryFn: ({ signal }) => portalApi.getDeploymentBatches(signal),
|
||||
});
|
||||
const addDeploymentGroup = useMutation({
|
||||
mutationFn: portalApi.addDeploymentGroup,
|
||||
const { data: services } = useQuery({
|
||||
queryKey: ["services"],
|
||||
queryFn: ({ signal }) => portalApi.getServices(signal),
|
||||
});
|
||||
const { data: templates } = useQuery({
|
||||
queryKey: ["templates"],
|
||||
queryFn: ({ signal }) => portalApi.getTemplates(signal),
|
||||
});
|
||||
const { data: templateCategories } = useQuery({
|
||||
queryKey: ["template-categories"],
|
||||
queryFn: ({ signal }) => portalApi.getTemplateCategories(signal),
|
||||
});
|
||||
const { data: virtualMachines } = useQuery({
|
||||
queryKey: ["virtual-machines"],
|
||||
queryFn: ({ signal }) => portalApi.getVirtualMachines(signal),
|
||||
});
|
||||
const addDeploymentBatch = useMutation({
|
||||
mutationFn: portalApi.addDeploymentBatch,
|
||||
onSuccess: async () => {
|
||||
setServiceId("");
|
||||
setTemplateId("");
|
||||
setVirtualMachineIds([]);
|
||||
setStatus("New");
|
||||
await queryClient.invalidateQueries({ queryKey: ["deploymentGroups"] });
|
||||
await queryClient.invalidateQueries({ queryKey: ["deployment-batches"] });
|
||||
await queryClient.invalidateQueries({ queryKey: ["deployments"] });
|
||||
},
|
||||
});
|
||||
|
||||
const selectedService = (services ?? []).find((service) => service.id === serviceId);
|
||||
const isOnPremService = selectedService ? !selectedService.isCloudService : false;
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageHeader title="Deployment Groups" description="Gruppen von Bereitstellungen je Template." />
|
||||
<PageHeader title="Deployments" description="Deployment Batches und deren Ausfuehrungen." />
|
||||
<FormSection
|
||||
onSubmit={(event) => {
|
||||
event.preventDefault();
|
||||
addDeploymentGroup.mutate({ status, templateId });
|
||||
addDeploymentBatch.mutate({
|
||||
status,
|
||||
templateId,
|
||||
virtualMachineIds: isOnPremService ? virtualMachineIds : undefined,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<FormGrid>
|
||||
<Field label="Template Id" required>
|
||||
<Input value={templateId} onChange={(_, data) => setTemplateId(data.value)} />
|
||||
<Field label="Service" required>
|
||||
<Combobox
|
||||
placeholder="Service waehlen"
|
||||
value={services?.find((service) => service.id === serviceId)?.name ?? ""}
|
||||
onOptionSelect={(_, data) => {
|
||||
const nextServiceId = data.optionValue ?? "";
|
||||
setServiceId(nextServiceId);
|
||||
setTemplateId("");
|
||||
setVirtualMachineIds([]);
|
||||
}}
|
||||
>
|
||||
{(services ?? []).map((service) => (
|
||||
<Option key={service.id} text={service.name} value={service.id}>
|
||||
{service.name}
|
||||
</Option>
|
||||
))}
|
||||
</Combobox>
|
||||
</Field>
|
||||
<Field label="Status" required validationMessage={addDeploymentGroup.error?.message}>
|
||||
<Input value={status} onChange={(_, data) => setStatus(data.value)} />
|
||||
<Field label="Template" required>
|
||||
<Combobox
|
||||
placeholder={serviceId ? "Template waehlen" : "Erst Service waehlen"}
|
||||
disabled={!serviceId}
|
||||
value={templates?.find((template) => template.id === templateId)?.name ?? ""}
|
||||
onOptionSelect={(_, data) => setTemplateId(data.optionValue ?? "")}
|
||||
>
|
||||
{(templates ?? [])
|
||||
.filter((template) => {
|
||||
const category = (templateCategories ?? []).find((entry) => entry.id === template.templateCategoryId);
|
||||
return category?.serviceId === serviceId;
|
||||
})
|
||||
.map((template) => (
|
||||
<Option key={template.id} text={template.name} value={template.id}>
|
||||
{template.name}
|
||||
</Option>
|
||||
))}
|
||||
</Combobox>
|
||||
</Field>
|
||||
<Field label="Status" required validationMessage={addDeploymentBatch.error?.message}>
|
||||
<Combobox value={status} onOptionSelect={(_, data) => setStatus(data.optionValue ?? "New")}>
|
||||
<Option value="New">New</Option>
|
||||
<Option value="Pending">Pending</Option>
|
||||
<Option value="Running">Running</Option>
|
||||
<Option value="Succeeded">Succeeded</Option>
|
||||
<Option value="Failed">Failed</Option>
|
||||
</Combobox>
|
||||
</Field>
|
||||
{isOnPremService && (
|
||||
<Field label="Virtual Machines" required>
|
||||
<div>
|
||||
{(virtualMachines ?? []).map((virtualMachine) => (
|
||||
<Checkbox
|
||||
key={virtualMachine.id}
|
||||
label={virtualMachine.name}
|
||||
checked={virtualMachineIds.includes(virtualMachine.id)}
|
||||
onChange={(_, data) => {
|
||||
if (data.checked) {
|
||||
setVirtualMachineIds((prev) => [...prev, virtualMachine.id]);
|
||||
} else {
|
||||
setVirtualMachineIds((prev) => prev.filter((id) => id !== virtualMachine.id));
|
||||
}
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</Field>
|
||||
)}
|
||||
</FormGrid>
|
||||
<FormActions>
|
||||
<Button
|
||||
appearance="primary"
|
||||
disabled={!templateId || !status || addDeploymentGroup.isPending}
|
||||
disabled={!templateId || !status || (isOnPremService && virtualMachineIds.length === 0) || addDeploymentBatch.isPending}
|
||||
type="submit"
|
||||
>
|
||||
Add deployment group
|
||||
Add deployment batch
|
||||
</Button>
|
||||
</FormActions>
|
||||
</FormSection>
|
||||
<DataState isLoading={isLoading} error={error} />
|
||||
{data && (
|
||||
<Table aria-label="Deployment groups">
|
||||
<Table aria-label="Deployment batches">
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHeaderCell>Status</TableHeaderCell>
|
||||
<TableHeaderCell>Id</TableHeaderCell>
|
||||
<TableHeaderCell>Actions</TableHeaderCell>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{data.map((deploymentGroup) => (
|
||||
<TableRow key={deploymentGroup.id}>
|
||||
<TableCell>{deploymentGroup.status ?? "Unknown"}</TableCell>
|
||||
<TableCell>{deploymentGroup.id}</TableCell>
|
||||
{data.map((deploymentBatch) => (
|
||||
<TableRow key={deploymentBatch.id}>
|
||||
<TableCell>{deploymentBatch.status ?? "Unknown"}</TableCell>
|
||||
<TableCell>{deploymentBatch.id}</TableCell>
|
||||
<TableCell>
|
||||
<div className={styles.actions}>
|
||||
<Tooltip content="Details" relationship="label">
|
||||
<Link to={`/deployments/${deploymentBatch.id}`}>
|
||||
<Button appearance="subtle" aria-label="Details" icon={<OpenRegular />} />
|
||||
</Link>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
|
||||
Reference in New Issue
Block a user