From 1a06a12b7c8f397e6f2c68197f8ca78d880e81d8 Mon Sep 17 00:00:00 2001 From: Bernt Christian Egeland Date: Fri, 7 Apr 2023 14:31:55 +0000 Subject: [PATCH] change network name, improved input element --- .devcontainer/init-cmd.sh | 0 src/components/elements/input.tsx | 23 ++++++- src/components/elements/inputField.tsx | 3 + src/icons/copy.tsx | 29 +++++++++ src/icons/edit.tsx | 4 +- src/pages/network/[id].tsx | 84 ++++++++++++++++++++++---- src/pages/profile/index.tsx | 2 + src/server/api/routers/adminRoute.ts | 40 +++++------- src/utils/ztApi.ts | 33 ++++++++-- 9 files changed, 174 insertions(+), 44 deletions(-) mode change 100644 => 100755 .devcontainer/init-cmd.sh create mode 100644 src/icons/copy.tsx diff --git a/.devcontainer/init-cmd.sh b/.devcontainer/init-cmd.sh old mode 100644 new mode 100755 diff --git a/src/components/elements/input.tsx b/src/components/elements/input.tsx index 07bc15fc..628fc1cb 100644 --- a/src/components/elements/input.tsx +++ b/src/components/elements/input.tsx @@ -2,11 +2,13 @@ import { useEffect, useRef } from "react"; interface PasswordInputProps { placeholder: string; - value: string; + value?: string; name: string; type: string; onChange: (event: React.ChangeEvent) => void; focus?: boolean; + className?: string; + defaultValue?: string; } const Input = ({ @@ -15,6 +17,8 @@ const Input = ({ name, onChange, type, + className, + defaultValue, focus = false, ...rest }: PasswordInputProps) => { @@ -25,14 +29,29 @@ const Input = ({ inputRef.current.focus(); } }, [focus]); + + useEffect(() => { + if (defaultValue && inputRef.current && onChange) { + const event = { + target: { + name: inputRef.current.name, + value: defaultValue, + }, + }; + onChange(event as React.ChangeEvent); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + return ( diff --git a/src/components/elements/inputField.tsx b/src/components/elements/inputField.tsx index ed84180e..7cabbac7 100644 --- a/src/components/elements/inputField.tsx +++ b/src/components/elements/inputField.tsx @@ -8,6 +8,7 @@ interface FieldConfig { type: string; placeholder: string; displayValue?: string; + defaultValue?: string; } interface FormProps { @@ -15,6 +16,7 @@ interface FormProps { isLoading?: boolean; placeholder?: string; fields: FieldConfig[]; + submitHandler: (formValues: { [key: string]: string; }) => Promise | string | void; @@ -71,6 +73,7 @@ const InputField = ({ value={formValues[field.name]} onChange={handleChange} name={field.name} + defaultValue={field.defaultValue} /> ))}
diff --git a/src/icons/copy.tsx b/src/icons/copy.tsx new file mode 100644 index 00000000..a121ed6b --- /dev/null +++ b/src/icons/copy.tsx @@ -0,0 +1,29 @@ +import React from "react"; + +interface Icon { + // add optional className prop + className?: string; + onClick?: () => void; +} + +const CopyIcon = ({ className, onClick, ...rest }: Icon) => ( + + + + + +); + +export default CopyIcon; diff --git a/src/icons/edit.tsx b/src/icons/edit.tsx index b96e95c7..e2c2d1a0 100644 --- a/src/icons/edit.tsx +++ b/src/icons/edit.tsx @@ -1,10 +1,10 @@ -interface IeditIcon { +interface Icon { // add optional className prop className?: string; onClick?: () => void; } -const EditIcon = ({ className, onClick, ...rest }: IeditIcon) => { +const EditIcon = ({ className, onClick, ...rest }: Icon) => { return ( { + const [state, setState] = useState({ + editNetworkName: false, + networkName: "", + }); const { query } = useRouter(); - const { data: networkById, isLoading: loadingNetwork } = - api.network.getNetworkById.useQuery( - { - nwid: query.id as string, - }, - { enabled: !!query.id, refetchInterval: 10000 } - ); + const { + data: networkById, + isLoading: loadingNetwork, + refetch: refetchNetwork, + } = api.network.getNetworkById.useQuery( + { + nwid: query.id as string, + }, + { enabled: !!query.id, refetchInterval: 10000 } + ); + const { mutate: updateNetwork } = api.network.updateNetwork.useMutation(); + const copy = useCopyToClipboard(); if (loadingNetwork) { return ; } const { network, members } = networkById; - // console.log(zombieMembers); + const changeNameHandler = (e: React.ChangeEvent) => { + e.preventDefault(); + updateNetwork( + { + nwid: network.nwid, + updateParams: { name: state.networkName }, + }, + { + onSuccess: () => { + void refetchNetwork(); + setState({ ...state, editNetworkName: false }); + }, + } + ); + }; + const eventHandler = (e: React.ChangeEvent) => { + setState({ ...state, [e.target.name]: e.target.value }); + }; return (
@@ -31,11 +61,43 @@ const NetworkById = () => {
Network ID: - {network?.nwid} + + {network?.nwid} + void copy[1](network?.nwid)} + /> +
Network Name: - {network?.name} + + {state.editNetworkName ? ( +
+ +
+ ) : ( + network?.name + )} + + setState({ + ...state, + editNetworkName: !state.editNetworkName, + }) + } + /> +
Network is diff --git a/src/pages/profile/index.tsx b/src/pages/profile/index.tsx index d16cfcbd..efb90197 100644 --- a/src/pages/profile/index.tsx +++ b/src/pages/profile/index.tsx @@ -31,6 +31,7 @@ const Profile = () => { name: "name", type: "text", placeholder: session?.user?.name, + defaultValue: session?.user?.name, }, ]} submitHandler={async (params) => @@ -52,6 +53,7 @@ const Profile = () => { name: "email", type: "text", placeholder: session?.user?.email, + defaultValue: session?.user?.email, }, ]} submitHandler={async (params) => diff --git a/src/server/api/routers/adminRoute.ts b/src/server/api/routers/adminRoute.ts index 2210768d..2b06aa42 100644 --- a/src/server/api/routers/adminRoute.ts +++ b/src/server/api/routers/adminRoute.ts @@ -1,4 +1,3 @@ -import { z } from "zod"; import { createTRPCRouter, adminRoleProtectedRoute } from "~/server/api/trpc"; import * as ztController from "~/utils/ztApi"; @@ -28,30 +27,23 @@ export const adminRouter = createTRPCRouter({ }, }); return users; - - // await ctx.prisma.user.findMany(); }), - getControllerStats: adminRoleProtectedRoute - // .input( - // z.object({ - // userid: z.number().optional(), - // }) - // ) - .query(async () => { - const networks = await ztController.get_controller_networks(); - const networkCount = networks.length; - let totalMembers = 0; - for (const network of networks) { - const members = await ztController.network_members(network); - totalMembers += Object.keys(members).length; - } + getControllerStats: adminRoleProtectedRoute.query(async () => { + const networks = await ztController.get_controller_networks(); + + const networkCount = networks.length; + let totalMembers = 0; + for (const network of networks) { + const members = await ztController.network_members(network); + totalMembers += Object.keys(members).length; + } - const controllerStatus = await ztController.get_controller_status(); - return { - networkCount, - totalMembers, - controllerStatus, - }; - }), + const controllerStatus = await ztController.get_controller_status(); + return { + networkCount, + totalMembers, + controllerStatus, + }; + }), }); diff --git a/src/utils/ztApi.ts b/src/utils/ztApi.ts index 3c14193f..ca524682 100644 --- a/src/utils/ztApi.ts +++ b/src/utils/ztApi.ts @@ -69,10 +69,21 @@ export const get_controller_networks = ZT_ADDR + "/controller/network", options ); - return data; - } catch (err) { - throw err; + } catch (error) { + if (axios.isAxiosError(error)) { + const axiosError = error as AxiosError; + // eslint-disable-next-line no-console + console.error(`Axios error: ${axiosError.message}`); + // eslint-disable-next-line no-console + console.error(`Status code: ${axiosError.response?.status}`); + // eslint-disable-next-line no-console + console.error(`Status text: ${axiosError.response?.statusText}`); + throw axiosError; + } + // eslint-disable-next-line no-console + console.error(`Unknown error: ${error.message}`); + throw error; } }; @@ -119,8 +130,20 @@ export const get_controller_status = async function () { try { const { data } = await axios.get(ZT_ADDR + "/status", options); return data as ZTControllerNodeStatus; - } catch (err) { - throw err; + } catch (error) { + if (axios.isAxiosError(error)) { + const axiosError = error as AxiosError; + // eslint-disable-next-line no-console + console.error(`Axios error: ${axiosError.message}`); + // eslint-disable-next-line no-console + console.error(`Status code: ${axiosError.response?.status}`); + // eslint-disable-next-line no-console + console.error(`Status text: ${axiosError.response?.statusText}`); + throw axiosError; + } + // eslint-disable-next-line no-console + console.error(`Unknown error: ${error.message}`); + throw error; } };