This commit is contained in:
Benjamin Toby 2026-03-10 13:07:47 +00:00
parent 29a8b17c61
commit 2363f9dc1f
5 changed files with 163 additions and 54 deletions

View File

@ -31,38 +31,36 @@ export default function ServiceClusterServer({ service, server }: Props) {
const [log, setLog] = useState<string>(); const [log, setLog] = useState<string>();
return ( return (
<Stack className="grid-cell gap-0" componentRef={elementRef as any}> <Stack className="gap-0">
<Stack className="grid-cell-content"> <Row className="w-full justify-between">
<Row className="w-full justify-between"> {/* <Row>
<Row> <code>{server.private_ip}</code>
<code>{server.private_ip}</code> </Row> */}
</Row> <Row>
<Row> {ServerTerminalTargets.map((targ, index) => {
{ServerTerminalTargets.map((targ, index) => { const is_active = targ.name == target;
const is_active = targ.name == target;
return ( return (
<Button <Button
title={`${targ.name}`} title={`${targ.name}`}
onClick={() => { onClick={() => {
setTarget(targ.name); setTarget(targ.name);
}} }}
size="smaller" size="smaller"
color="gray" color="gray"
variant={is_active ? undefined : "outlined"} variant={is_active ? undefined : "outlined"}
> key={index}
{targ.name} >
</Button> {targ.name}
); </Button>
})} );
</Row> })}
</Row> </Row>
<ServiceClusterServerLogSelector </Row>
{...{ server, service, setLog }} <ServiceClusterServerLogSelector {...{ server, service, setLog }} />
/>
</Stack>
<hr /> <hr />
{isIntersecting ? ( <ServiceClusterServerViews {...{ server, service, target, log }} />
{/* {isIntersecting ? (
<ServiceClusterServerViews <ServiceClusterServerViews
{...{ server, service, target, log }} {...{ server, service, target, log }}
/> />
@ -70,7 +68,7 @@ export default function ServiceClusterServer({ service, server }: Props) {
<Center> <Center>
<Loading /> <Loading />
</Center> </Center>
)} )} */}
</Stack> </Stack>
); );
} }

View File

@ -1,37 +1,61 @@
import Stack from "@/twui/components/layout/Stack"; import Stack from "@/twui/components/layout/Stack";
import { useContext } from "react"; import { useContext, useState } from "react";
import { AppContext } from "@/src/pages/_app"; import { AppContext } from "@/src/pages/_app";
import { ParsedDeploymentServiceConfig } from "@/src/types"; import {
NormalizedServerObject,
ParsedDeploymentServiceConfig,
} from "@/src/types";
import Row from "@/twui/components/layout/Row"; import Row from "@/twui/components/layout/Row";
import H2 from "@/twui/components/layout/H2"; import H2 from "@/twui/components/layout/H2";
import ServiceClusterServer from "./cluster-server"; import ServiceClusterServer from "./cluster-server";
import Button from "@/twui/components/layout/Button";
import { twMerge } from "tailwind-merge";
type Props = { type Props = {
service: ParsedDeploymentServiceConfig; service: ParsedDeploymentServiceConfig;
cluster_index: number;
}; };
export default function ServiceCluster({ service, cluster_index }: Props) { export default function ServiceCluster({ service }: Props) {
const { pageProps } = useContext(AppContext); const { pageProps } = useContext(AppContext);
const cluster_servers = service.servers; const cluster_servers = service.servers;
const [targetServer, setTargetServer] = useState<
NormalizedServerObject | undefined
>(cluster_servers?.[0]);
return ( return (
<Stack className="w-full grid-cell col-span-1 gap-0"> <Stack className="w-full grid-cell col-span-1 gap-0">
<Stack className="grid-cell-content"> <Row className="p-4">
<H2>Cluster #{cluster_index}</H2>
</Stack>
<hr />
<Row className="nested-grid-frame xl:grid-cols-2">
{cluster_servers?.map((server, index) => { {cluster_servers?.map((server, index) => {
const is_active =
server?.private_ip == targetServer?.private_ip;
return ( return (
<ServiceClusterServer <Button
server={server} title={`Cluster ${index + 1}`}
service={service}
key={index} key={index}
/> color="gray"
variant={is_active ? undefined : "outlined"}
size="small"
onClick={() => {
setTargetServer(server);
}}
>
<span
className={twMerge(
is_active ? "font-semibold" : "",
)}
>
{server.private_ip}
</span>
</Button>
); );
})} })}
</Row> </Row>
{targetServer ? (
<ServiceClusterServer server={targetServer} service={service} />
) : undefined}
</Stack> </Stack>
); );
} }

View File

@ -1,7 +1,16 @@
import Stack from "@/twui/components/layout/Stack"; import Stack from "@/twui/components/layout/Stack";
import { useContext } from "react"; import { useContext, useState } from "react";
import { AppContext } from "@/src/pages/_app"; import { AppContext } from "@/src/pages/_app";
import ServiceCluster from "../(partials)/cluster"; import ServiceCluster from "../(partials)/cluster";
import {
NormalizedServerObject,
ParsedDeploymentServiceConfig,
} from "@/src/types";
import Button from "@/twui/components/layout/Button";
import Row from "@/twui/components/layout/Row";
import { twMerge } from "tailwind-merge";
import Select from "@/twui/components/form/Select";
import ServiceClusterServer from "../(partials)/cluster-server";
export default function ServiceClusters() { export default function ServiceClusters() {
const { pageProps } = useContext(AppContext); const { pageProps } = useContext(AppContext);
@ -9,18 +18,93 @@ export default function ServiceClusters() {
const all_services = [service, ...(children_services || [])]; const all_services = [service, ...(children_services || [])];
const [targetCluster, setTargetCluster] = useState<
ParsedDeploymentServiceConfig | undefined
>(service || undefined);
const clusterIndex =
all_services.findIndex(
(srv) => srv?.service_name == targetCluster?.service_name,
) + 1;
const cluster_servers = targetCluster?.servers;
const [targetServer, setTargetServer] = useState<
NormalizedServerObject | undefined
>(cluster_servers?.[0]);
return ( return (
<Stack className="w-full nested-grid-frame grid-cols-1"> <Stack className="w-full nested-grid-frame grid-cols-1">
{all_services.map((srv, index) => { <Stack className="grid-cell gap-0">
if (!srv) return null; <Row className="p-4 flex-nowrap">
return ( <Select
<ServiceCluster options={all_services.map((srv) => ({
key={index} value: srv?.service_name!,
service={srv} title: `Cluster #${clusterIndex}`,
cluster_index={index + 1} }))}
wrapperWrapperProps={{
className: `max-w-[250px]`,
}}
changeHandler={(v) => {
setTargetCluster(
all_services.find(
(s) => s?.service_name == v,
) || undefined,
);
}}
/> />
);
})} {cluster_servers?.[0] ? (
<Select
options={cluster_servers.map((server) => ({
value: server?.private_ip!,
title: `${server?.private_ip}`,
}))}
wrapperWrapperProps={{
className: `max-w-[250px]`,
}}
changeHandler={(v) => {
setTargetServer(
cluster_servers.find(
(s) => s?.private_ip == v,
) || undefined,
);
}}
/>
) : undefined}
{/* {all_services.map((srv, index) => {
const is_active =
srv?.service_name == targetCluster?.service_name;
if (!srv) return null;
return (
<Button
title={`Cluster ${index + 1}`}
key={index}
color="gray"
variant={is_active ? undefined : "outlined"}
size="small"
>
<span
className={twMerge(
is_active ? "font-semibold" : "",
)}
>
Cluster {index + 1}
</span>
</Button>
);
})} */}
</Row>
<hr />
{targetCluster ? (
<ServiceCluster service={targetCluster} />
) : undefined}
{targetServer && service ? (
<ServiceClusterServer
server={targetServer}
service={service}
/>
) : undefined}
</Stack>
</Stack> </Stack>
); );
} }

View File

@ -1,4 +1,3 @@
import Stack from "@/twui/components/layout/Stack";
import { Fragment, useContext } from "react"; import { Fragment, useContext } from "react";
import { AppContext } from "@/src/pages/_app"; import { AppContext } from "@/src/pages/_app";
import twuiSlugToNormalText from "@/twui/components/utils/slug-to-normal-text"; import twuiSlugToNormalText from "@/twui/components/utils/slug-to-normal-text";

View File

@ -76,6 +76,10 @@
@apply text-primary-text; @apply text-primary-text;
} }
.twui-button-primary * {
@apply text-primary-text;
}
.twui-h1, .twui-h1,
.twui-h2, .twui-h2,
.twui-h3 { .twui-h3 {