This commit is contained in:
karamvir
2023-08-10 20:30:54 -07:00
parent e1fbbe7c4e
commit af7229acb0
7 changed files with 324 additions and 183 deletions

View File

@@ -1,6 +1,5 @@
import { useRead } from "@hooks";
import { BuilderConfig, Resource } from "@monitor/client/dist/types";
import { ReactNode, useState } from "react";
import { Resource } from "@monitor/client/dist/types";
import { Fragment, ReactNode } from "react";
const keys = <T extends Record<string, unknown>>(obj: T) =>
Object.keys(obj) as Array<keyof T>;
@@ -12,15 +11,17 @@ export const ConfigAgain = <T extends Resource<unknown, unknown>["config"]>({
}: {
config: T;
update: Partial<T>;
components: {
components: Partial<{
[K in keyof T]: (value: T[K]) => ReactNode;
};
}>;
}) => {
return (
<>
{keys(components).map((key) => {
const value = update[key] ?? config[key];
return <>{components[key]?.(value)}</>;
return (
<Fragment key={key.toString()}>{components[key]?.(value)}</Fragment>
);
})}
</>
);
@@ -39,27 +40,3 @@ export const VariantConfig = <P, T extends { type: string; params: P }>({
}) => {
return <>{config}</>;
};
export const Builder = ({ id }: { id: string }) => {
const builder = useRead("GetBuilder", { id }).data;
if (!builder?.config) return null;
const [update, set] = useState<{
type: BuilderConfig["type"];
params: Partial<BuilderConfig["params"]>;
}>({ type: builder.config.type, params: {} });
return (
<VariantConfig
config={builder.config}
update={update}
components={{
Server: {
id: (id) => <div>{id}</div>,
},
Aws: {
ami_id:
}
}}
/>
);
};

View File

@@ -0,0 +1,38 @@
import { Input } from "@ui/input";
import { Switch } from "@ui/switch";
export const ConfigInput = ({
label,
value,
onChange,
}: {
label: string;
value: string | number | undefined;
onChange: (value: string) => void;
}) => (
<div className="flex justify-between items-center border-b pb-4">
<div className="capitalize"> {label} </div>
<Input
className="max-w-[400px]"
type={typeof value === "number" ? "number" : undefined}
value={value}
onChange={(e) => onChange(e.target.value)}
// disabled={loading}
/>
</div>
);
export const ConfigSwitch = ({
label,
value,
onChange,
}: {
label: boolean;
value: boolean | undefined;
onChange: (value: boolean) => void;
}) => (
<div className="flex justify-between items-center border-b pb-4">
<div className="capitalize"> {label} </div>
<Switch checked={value} onCheckedChange={onChange} />
</div>
);

View File

@@ -1,3 +1,6 @@
import { ConfirmUpdate } from "@components/config/confirm-update";
import { Button } from "@ui/button";
import { Settings, Save, History } from "lucide-react";
import { ReactNode } from "react";
interface PageProps {
@@ -39,3 +42,33 @@ export const Section = ({ title, icon, actions, children }: SectionProps) => (
{children}
</div>
);
export const ConfigLayout = ({
content,
children,
onConfirm,
onReset,
}: {
content: any;
children: ReactNode;
onConfirm: () => void;
onReset: () => void;
}) => (
<Section
title="Config"
icon={<Settings className="w-4 h-4" />}
actions={
<div className="flex gap-4">
<Button variant="outline" intent="warning" onClick={onReset}>
<History className="w-4 h-4" />
</Button>
<ConfirmUpdate
content={JSON.stringify(content, null, 2)}
onConfirm={onConfirm}
/>
</div>
}
>
{children}
</Section>
);

View File

@@ -1,15 +1,13 @@
import { ResourceCard } from "@layouts/card";
import { Bot, Cloud, Factory, History, Settings } from "lucide-react";
import { Bot, Cloud, Factory } from "lucide-react";
import { ResourceUpdates } from "@components/updates/resource";
import { useAddRecentlyViewed, useRead, useWrite } from "@hooks";
import { Resource } from "@layouts/resource";
import { Link, useParams } from "react-router-dom";
import { Types } from "@monitor/client";
import { useState } from "react";
import { Section } from "@layouts/page";
import { Button } from "@ui/button";
import { ConfirmUpdate } from "@components/config/confirm-update";
import { ConfigAgain, VariantConfig } from "@components/config/again";
import { ConfigLayout } from "@layouts/page";
import { ConfigAgain } from "@components/config/again";
import { Input } from "@ui/input";
import {
Select,
@@ -18,6 +16,10 @@ import {
SelectTrigger,
SelectValue,
} from "@ui/select";
import { ServersSelector } from "@resources/deployment/config";
import { Card, CardContent, CardHeader, CardTitle } from "@ui/card";
import { Button } from "@ui/button";
import { ConfigInput } from "@components/config/util";
export const BuilderName = ({ id }: { id: string }) => {
const builders = useRead("ListBuilders", {}).data;
@@ -64,142 +66,160 @@ const BuilderTypeSelector = ({
</SelectTrigger>
<SelectContent>
<SelectItem value={"Aws"}>Aws</SelectItem>
{/* <SelectItem value={"Server"}>Server</SelectItem> */}
<SelectItem value={"Server"}>Server</SelectItem>
</SelectContent>
</Select>
);
const ConfigInput = ({
label,
value,
onChange,
const ServerConfig = ({
config,
update,
set,
}: {
label: string;
value: string | number;
onChange: (value: string) => void;
config: Types.ServerBuilderConfig;
update: Partial<Types.ServerBuilderConfig>;
set: (update: Partial<Types.ServerBuilderConfig>) => void;
}) => (
<div className="flex justify-between items-center border-b pb-4">
<div className="capitalize"> {label} </div>
<Input
className="max-w-[400px]"
type={typeof value === "number" ? "number" : undefined}
value={value}
onChange={(e) => onChange(e.target.value)}
// disabled={loading}
/>
</div>
<ConfigAgain
config={config}
update={update}
components={{
id: (id) => (
<div className="flex justify-between items-center border-b pb-4">
Select Server
<ServersSelector selected={id} onSelect={(id) => set({ id })} />
</div>
),
}}
/>
);
const BuilderConfig = ({ id }: { id: string }) => {
const builder = useRead("GetBuilder", { id }).data;
if (!builder?.config) return null;
const AwsBuilderConfig = ({
config,
update,
set,
}: {
config: Types.AwsBuilderConfig;
update: Partial<Types.AwsBuilderConfig>;
set: (update: Partial<Types.AwsBuilderConfig>) => void;
}) => (
<ConfigAgain
config={config}
update={update}
components={{
region: (region) => (
<ConfigInput
label="Region"
value={region}
onChange={(region) => set({ region })}
/>
),
instance_type: (instance_type) => (
<ConfigInput
label="Instance Type"
value={instance_type}
onChange={(instance_type) => set({ instance_type })}
/>
),
const [type, setT] = useState(builder.config.type);
const [update, set] = useState<{
type: Types.BuilderConfig["type"];
params: Partial<Types.BuilderConfig["params"]>;
}>({ type: builder.config.type, params: {} });
volume_gb: (volume_gb) => (
<ConfigInput
label="Region"
value={volume_gb}
onChange={(ami_id) => set({ ami_id })}
/>
),
ami_id: (ami_id) => (
<ConfigInput
label="AMI Id"
value={ami_id}
onChange={(ami_id) => set({ ami_id })}
/>
),
subnet_id: (subnet_id) => (
<ConfigInput
label="Subnet Id"
value={subnet_id}
onChange={(subnet_id) => set({ subnet_id })}
/>
),
key_pair_name: (key_pair_name) => (
<ConfigInput
label="Subnet Id"
value={key_pair_name}
onChange={(n) => set({ key_pair_name })}
/>
),
assign_public_ip: () => <div>assign_public_ip</div>,
// security_group_ids: (ids) => <div>sec group ids</div>,
// github_accounts: () => <div>github_accounts</div>,
// docker_accounts: () => <div>docker_accounts</div>,
}}
/>
);
const BuilderConfig = ({
id,
config,
}: {
id: string;
config: Types.BuilderConfig;
}) => {
const [update, set] = useState({ type: config.type, params: {} });
const { mutate } = useWrite("UpdateBuilder");
return (
<Section
title="Config"
icon={<Settings className="w-4 h-4" />}
actions={
<div className="flex gap-4">
<Button
variant="outline"
intent="warning"
onClick={() => set({ type: builder.config.type, params: {} })}
>
<History className="w-4 h-4" />
</Button>
<ConfirmUpdate
content={JSON.stringify(update, null, 2)}
onConfirm={() => {
mutate({
id,
config: update,
});
}}
/>
</div>
}
<ConfigLayout
content={update}
onConfirm={() => mutate({ id, config: update })}
onReset={() => set({ type: config.type, params: {} })}
>
<BuilderTypeSelector
selected={type ?? builder.config.type}
onSelect={(type) => setT(type)}
/>
{type === "Server" && (
<ConfigAgain
config={builder.config.params}
update={update ?? {}}
components={{
id: (selected) => <div></div>,
}}
/>
)}
{type === "Aws" && (
<VariantConfig
config={builder.config.params}
update={update ?? {}}
components={{
region: (region) => (
<ConfigInput
label="Region"
value={region}
onChange={(region) => set((u) => ({ ...u, region }))}
<div className="flex gap-4">
<div className="flex flex-col gap-4 w-[300px]">
<Button>General</Button>
</div>
<Card>
<CardHeader className="border-b">
<CardTitle>General</CardTitle>
</CardHeader>
<CardContent className="flex flex-col gap-4 mt-6">
<div className="flex justify-between items-center border-b pb-4">
Builder Type
<BuilderTypeSelector
selected={update.type}
onSelect={(type) => set({ type, params: {} })}
/>
),
instance_type: (instance_type) => (
<ConfigInput
label="Instance Type"
value={instance_type}
onChange={(t) => set((u) => ({ ...u, instance_type: t }))}
</div>
{update.type === "Server" && (
<ServerConfig
config={config.params as Types.ServerBuilderConfig}
update={update.params}
set={(u) =>
set((p) => ({ ...p, params: { ...p.params, ...u } }))
}
/>
),
volume_gb: (volume_gb) => (
<ConfigInput
label="Region"
value={volume_gb}
onChange={(ami_id) => set((u) => ({ ...u, ami_id }))}
)}
{update.type === "Aws" && (
<AwsBuilderConfig
config={config.params as Types.AwsBuilderConfig}
update={update.params}
set={(u) =>
set((p) => ({ ...p, params: { ...p.params, ...u } }))
}
/>
),
ami_id: (ami_id) => (
<ConfigInput
label="AMI Id"
value={ami_id}
onChange={(ami_id) => set((u) => ({ ...u, ami_id }))}
/>
),
subnet_id: (subnet_id) => (
<ConfigInput
label="Subnet Id"
value={subnet_id}
onChange={(subnet_id) => set((u) => ({ ...u, subnet_id }))}
/>
),
security_group_ids: (ids) => <div>sec group ids</div>,
key_pair_name: (key_pair_name) => (
<ConfigInput
label="Subnet Id"
value={key_pair_name}
onChange={(n) => set((u) => ({ ...u, key_pair_name: n }))}
/>
),
assign_public_ip: () => <div>assign_public_ip</div>,
// github_accounts: () => <div>github_accounts</div>,
// docker_accounts: () => <div>docker_accounts</div>,
}}
/>
)}
</Section>
)}
</CardContent>
</Card>
</div>
</ConfigLayout>
);
};
const BCWrapper = ({ id }: { id: string }) => {
const config = useRead("GetBuilder", { id }).data?.config;
if (!config) return null;
return <BuilderConfig id={id} config={config} />;
};
export const BuilderPage = () => {
const id = useParams().builderId;
@@ -209,7 +229,7 @@ export const BuilderPage = () => {
return (
<Resource title={<BuilderName id={id} />} info={<></>} actions={<></>}>
<ResourceUpdates type="Builder" id={id} />
<BuilderConfig id={id} />
<BCWrapper id={id} />
</Resource>
);
};

View File

@@ -1,10 +1,10 @@
import { ResourceUpdates } from "@components/updates/resource";
import { useRead, useAddRecentlyViewed } from "@hooks";
import { useRead, useAddRecentlyViewed, useWrite } from "@hooks";
import { ResourceCard } from "@layouts/card";
import { Resource } from "@layouts/resource";
import { CardDescription } from "@ui/card";
import { useParams, Link } from "react-router-dom";
import { SerCon, ServerConfig } from "./config";
import { SerCon } from "./config";
import { ServerStats } from "./stats";
import {
ServerName,
@@ -12,6 +12,101 @@ import {
ServerSpecs,
ServerRegion,
} from "./util";
import { ServerConfig } from "@monitor/client/dist/types";
import { useState } from "react";
import { Types } from "@monitor/client";
import { ConfigLayout } from "@layouts/page";
import { Button } from "@ui/button";
import { ConfigAgain } from "@components/config/again";
import { ConfigInput } from "@components/config/util";
export const ServerCard = ({ id }: { id: string }) => {
const servers = useRead("ListServers", {}).data;
const server = servers?.find((server) => server.id === id);
if (!server) return null;
return (
<Link to={`/servers/${server.id}`} key={server.id}>
<ResourceCard
title={server.name}
description={server.info.status}
statusIcon={<ServerStatusIcon serverId={server.id} />}
// icon={<Server className="w-4 h-4" />}
>
<div className="flex flex-col text-sm">
<ServerSpecs server_id={server.id} />
<ServerRegion serverId={server.id} />
</div>
</ResourceCard>
</Link>
);
};
const ServerConfigInner = ({
id,
config,
}: {
id: string;
config: Types.ServerConfig;
}) => {
const [update, set] = useState<Partial<Types.ServerConfig>>({});
const [show, setShow] = useState("general");
const { mutate } = useWrite("UpdateServer");
<ConfigLayout
content={update}
onConfirm={() => mutate({ id, config: update })}
onReset={() => set({})}
>
<div className="flex gap-4">
<div className="flex flex-col gap-4 w-[300px]">
<Button>General</Button>
</div>
{show === "general" && (
<ConfigAgain
config={config}
update={update}
components={{
address: (value) => (
<ConfigInput
label="Address"
value={value}
onChange={(address) => set((p) => ({ ...p, address }))}
/>
),
region: (value) => (
<ConfigInput
label="region"
value={value}
onChange={(region) => set((p) => ({ ...p, region }))}
/>
),
address: (value) => (
<ConfigInput
label="Address"
value={value}
onChange={(address) => set((p) => ({ ...p, address }))}
/>
),
address: (value) => (
<ConfigInput
label="Address"
value={value}
onChange={(address) => set((p) => ({ ...p, address }))}
/>
),
}}
/>
)}
</div>
</ConfigLayout>;
};
const ServerConfig = ({ id }: { id: string }) => {
const config = useRead("GetServer", { id }).data?.config;
if (!config) return null;
return <div></div>;
};
export const ServerPage = () => {
const id = useParams().serverId;
@@ -37,25 +132,3 @@ export const ServerPage = () => {
</Resource>
);
};
export const ServerCard = ({ id }: { id: string }) => {
const servers = useRead("ListServers", {}).data;
const server = servers?.find((server) => server.id === id);
if (!server) return null;
return (
<Link to={`/servers/${server.id}`} key={server.id}>
<ResourceCard
title={server.name}
description={server.status}
statusIcon={<ServerStatusIcon serverId={server.id} />}
// icon={<Server className="w-4 h-4" />}
>
<div className="flex flex-col text-sm">
<ServerSpecs server_id={server.id} />
<ServerRegion serverId={server.id} />
</div>
</ResourceCard>
</Link>
);
};

View File

@@ -17,7 +17,7 @@ export const ServerInfo = ({ serverId }: { serverId: string | undefined }) => {
<div className="flex items-center gap-4 text-muted-foreground">
<div className="flex items-center gap-2">
<ServerStatusIcon serverId={serverId} />
<div> {server?.status}</div>
<div> {server?.info.status}</div>
</div>
<CardDescription className="hidden md:block">|</CardDescription>
{serverId && <ServerSpecs server_id={serverId} />}
@@ -57,7 +57,7 @@ export const ServerRegion = ({
return (
<div className="flex gap-2 items-center text-muted-foreground">
<MapPin className="w-4 h-4" />
{server?.region || "region unknown"}
{server?.info.region || "region unknown"}
</div>
);
};
@@ -75,9 +75,9 @@ export const ServerStatusIcon = ({
<Server
className={cn(
"w-4 h-4 stroke-primary",
server?.status === ServerStatus.Ok && "fill-green-500",
server?.status === ServerStatus.NotOk && "fill-red-500",
server?.status === ServerStatus.Disabled && "fill-blue-500",
server?.info.status === ServerStatus.Ok && "fill-green-500",
server?.info.status === ServerStatus.NotOk && "fill-red-500",
server?.info.status === ServerStatus.Disabled && "fill-blue-500",
sm && "w-3 h-3"
)}
/>

View File

@@ -300,4 +300,4 @@ export function readableImageNameTag(
}
export const fmt_update_date = (d: Date) =>
`${d.getDate()}/${d.getMonth()} @ ${d.getHours()}:${d.getMinutes()}`;
`${d.getDate()}/${d.getMonth() + 1} @ ${d.getHours()}:${d.getMinutes()}`;