- Updated DeploymentExecution and related types to use targetId instead of virtualMachineId. - Introduced new types for DeploymentRule, DeploymentRuleStep, and related entities. - Added DeploymentRulesPage for managing deployment rules with CRUD operations. - Created TargetDetailsPage and TargetsPage for managing targets with linking and unlinking functionality. - Enhanced UI components with Fluent UI for better user experience. - Implemented data fetching and state management using React Query.
208 lines
7.2 KiB
TypeScript
208 lines
7.2 KiB
TypeScript
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
import {
|
|
Badge,
|
|
Button,
|
|
makeStyles,
|
|
MessageBar,
|
|
MessageBarBody,
|
|
shorthands,
|
|
Table,
|
|
TableBody,
|
|
TableCell,
|
|
TableHeader,
|
|
TableHeaderCell,
|
|
TableRow,
|
|
Text,
|
|
Title3,
|
|
tokens,
|
|
Tooltip,
|
|
} from "@fluentui/react-components";
|
|
import { ArrowLeftRegular, DeleteRegular, OpenRegular } from "@fluentui/react-icons";
|
|
import { Link, useParams } from "react-router-dom";
|
|
import { portalApi } from "../api/portalApi";
|
|
import { DataState } from "../components/DataState";
|
|
import { PageHeader } from "../components/PageHeader";
|
|
|
|
const useStyles = makeStyles({
|
|
backLink: {
|
|
display: "inline-flex",
|
|
marginBottom: "18px",
|
|
textDecorationLine: "none",
|
|
},
|
|
details: {
|
|
display: "grid",
|
|
gap: "14px",
|
|
gridTemplateColumns: "repeat(2, minmax(180px, 1fr))",
|
|
marginBottom: "24px",
|
|
maxWidth: "720px",
|
|
...shorthands.border("1px", "solid", tokens.colorNeutralStroke2),
|
|
...shorthands.borderRadius("8px"),
|
|
...shorthands.padding("18px"),
|
|
},
|
|
field: {
|
|
display: "grid",
|
|
gap: "4px",
|
|
minWidth: 0,
|
|
},
|
|
value: {
|
|
overflowWrap: "anywhere",
|
|
},
|
|
sectionTitle: {
|
|
marginBottom: "12px",
|
|
},
|
|
actions: {
|
|
display: "flex",
|
|
gap: "4px",
|
|
...shorthands.padding("2px", "0"),
|
|
},
|
|
});
|
|
|
|
export function EnvironmentDetailsPage() {
|
|
const styles = useStyles();
|
|
const queryClient = useQueryClient();
|
|
const { id } = useParams();
|
|
const { data, error, isLoading } = useQuery({
|
|
enabled: Boolean(id),
|
|
queryKey: ["environment", id, "domains"],
|
|
queryFn: ({ signal }) => portalApi.getEnvironmentDomains(id!, signal),
|
|
});
|
|
const links = data?.environmentDomains?.filter((link) => link.domain) ?? [];
|
|
const unlinkDomainFromEnvironment = useMutation({
|
|
mutationFn: ({ domainId, environmentId }: { domainId: string; environmentId: string }) =>
|
|
portalApi.unlinkDomainFromEnvironment(domainId, environmentId),
|
|
onSuccess: async () => {
|
|
await queryClient.invalidateQueries({ queryKey: ["environment", id, "domains"] });
|
|
await queryClient.invalidateQueries({ queryKey: ["domains"] });
|
|
await queryClient.invalidateQueries({ queryKey: ["environments"] });
|
|
},
|
|
});
|
|
|
|
return (
|
|
<>
|
|
<Link className={styles.backLink} to="/environments">
|
|
<Button appearance="subtle" icon={<ArrowLeftRegular />}>
|
|
Environments
|
|
</Button>
|
|
</Link>
|
|
<PageHeader title={data?.name ?? "Environment"} description="Details und verknuepfte Domains." />
|
|
<DataState isLoading={isLoading} error={error} />
|
|
{data && (
|
|
<>
|
|
<section className={styles.details} aria-label="Environment details">
|
|
<div className={styles.field}>
|
|
<Text size={200}>Name</Text>
|
|
<Text className={styles.value} weight="semibold">
|
|
{data.name}
|
|
</Text>
|
|
</div>
|
|
<div className={styles.field}>
|
|
<Text size={200}>Id</Text>
|
|
<Text className={styles.value} weight="semibold">
|
|
{data.id}
|
|
</Text>
|
|
</div>
|
|
<div className={styles.field}>
|
|
<Text size={200}>Environment Stage</Text>
|
|
<Text className={styles.value} weight="semibold">
|
|
{data.environmentType}
|
|
</Text>
|
|
</div>
|
|
<div className={styles.field}>
|
|
<Text size={200}>Hosting Type</Text>
|
|
<Text className={styles.value} weight="semibold">
|
|
{data.hostingType}
|
|
</Text>
|
|
</div>
|
|
<div className={styles.field}>
|
|
<Text size={200}>Cloud Enabled</Text>
|
|
<Text className={styles.value} weight="semibold">
|
|
{data.hostingType === "OnPrem" ? "Nein" : "Ja"}
|
|
</Text>
|
|
</div>
|
|
<div className={styles.field}>
|
|
<Text size={200}>Provider Type</Text>
|
|
<Text className={styles.value} weight="semibold">
|
|
{data.hostingType === "OnPrem" ? data.providerType : ""}
|
|
</Text>
|
|
</div>
|
|
{data.hostingType !== "OnPrem" && (
|
|
<div className={styles.field}>
|
|
<Text size={200}>Tenant Id</Text>
|
|
<Text className={styles.value} weight="semibold">
|
|
{data.tenantId}
|
|
</Text>
|
|
</div>
|
|
)}
|
|
{data.hostingType === "AzureTenant" && (
|
|
<div className={styles.field}>
|
|
<Text size={200}>Subscription Id</Text>
|
|
<Text className={styles.value} weight="semibold">
|
|
{data.subscriptionId}
|
|
</Text>
|
|
</div>
|
|
)}
|
|
</section>
|
|
|
|
<Title3 className={styles.sectionTitle}>Linked Domains</Title3>
|
|
{links.length === 0 ? (
|
|
<MessageBar>
|
|
<MessageBarBody>Dieses Environment ist noch mit keiner Domain verknuepft.</MessageBarBody>
|
|
</MessageBar>
|
|
) : (
|
|
<Table aria-label="Linked domains">
|
|
<TableHeader>
|
|
<TableRow>
|
|
<TableHeaderCell>Name</TableHeaderCell>
|
|
<TableHeaderCell>FQDN</TableHeaderCell>
|
|
<TableHeaderCell>NetBIOS</TableHeaderCell>
|
|
<TableHeaderCell>Status</TableHeaderCell>
|
|
<TableHeaderCell>Actions</TableHeaderCell>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
{links.map((link) => (
|
|
<TableRow key={link.domain!.id}>
|
|
<TableCell>{link.domain!.name}</TableCell>
|
|
<TableCell>{link.domain!.fqdn}</TableCell>
|
|
<TableCell>{link.domain!.netBIOS}</TableCell>
|
|
<TableCell>
|
|
<Badge appearance="filled" color="success">
|
|
Linked
|
|
</Badge>
|
|
</TableCell>
|
|
<TableCell>
|
|
<div className={styles.actions}>
|
|
<Tooltip content="Details" relationship="label">
|
|
<Link to={`/domains/${link.domain!.id}`}>
|
|
<Button appearance="subtle" aria-label="Details" icon={<OpenRegular />} />
|
|
</Link>
|
|
</Tooltip>
|
|
<Tooltip content="Unlink" relationship="label">
|
|
<Button
|
|
appearance="subtle"
|
|
aria-label="Unlink"
|
|
disabled={unlinkDomainFromEnvironment.isPending}
|
|
icon={<DeleteRegular />}
|
|
onClick={() => {
|
|
if (!id) return;
|
|
unlinkDomainFromEnvironment.mutate({
|
|
domainId: link.domain!.id,
|
|
environmentId: id,
|
|
});
|
|
}}
|
|
/>
|
|
</Tooltip>
|
|
</div>
|
|
</TableCell>
|
|
</TableRow>
|
|
))}
|
|
</TableBody>
|
|
</Table>
|
|
)}
|
|
</>
|
|
)}
|
|
</>
|
|
);
|
|
}
|
|
|