From 725daea5ebc58390a300f35e21b26dac7e2c2738 Mon Sep 17 00:00:00 2001 From: Milad Sadeghi Date: Wed, 4 Dec 2024 09:25:00 +0330 Subject: [PATCH 01/16] feat(web): Add Ansible Template route with placeholder Services page - Set up the route for "Ansible Template" - Created an initial Services page under this route (currently contains no functionality) --- web/src/App.tsx | 11 +++++- web/src/components/navbar/navbar.tsx | 4 +++ web/src/pages/ansible/components/layout.tsx | 40 +++++++++++++++++++++ web/src/pages/ansible/docker/docker.tsx | 7 ++++ web/src/pages/ansible/kuber/kuber.tsx | 7 ++++ web/src/pages/ansible/nginx/nginx.tsx | 7 ++++ 6 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 web/src/pages/ansible/components/layout.tsx create mode 100644 web/src/pages/ansible/docker/docker.tsx create mode 100644 web/src/pages/ansible/kuber/kuber.tsx create mode 100644 web/src/pages/ansible/nginx/nginx.tsx diff --git a/web/src/App.tsx b/web/src/App.tsx index ae9a0aa9..501f4910 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -12,12 +12,16 @@ import { Installation, S3, } from '@/pages'; +import { AnsibleLayout } from './pages/ansible/components/layout'; +import DockerAnsible from './pages/ansible/docker/docker'; +import NginxAnsible from './pages/ansible/nginx/nginx'; +import KubernetesAnsible from './pages/ansible/kuber/kuber'; function App() { const location = useLocation(); return (
-
+
}> } /> @@ -30,6 +34,11 @@ function App() { } /> } /> + }> + } /> + } /> + } /> + } /> diff --git a/web/src/components/navbar/navbar.tsx b/web/src/components/navbar/navbar.tsx index be296d75..6c7ee758 100644 --- a/web/src/components/navbar/navbar.tsx +++ b/web/src/components/navbar/navbar.tsx @@ -23,6 +23,10 @@ const navbar = [ url: '/helm-template', title: 'Helm Template', }, + { + url: '/ansible-template', + title: 'Ansible Template', + }, ]; const Navbar: FC = () => { diff --git a/web/src/pages/ansible/components/layout.tsx b/web/src/pages/ansible/components/layout.tsx new file mode 100644 index 00000000..d7f1abc7 --- /dev/null +++ b/web/src/pages/ansible/components/layout.tsx @@ -0,0 +1,40 @@ +import { FC } from 'react'; +import { NavLink, Outlet } from 'react-router'; + +const menu = [ + { + url: 'nginx', + title: 'Nginx Service', + }, + { + url: 'docker', + title: 'Docker Service', + }, + { + url: 'kuber', + title: 'Kubernetes Service', + }, +]; + +export const AnsibleLayout: FC = () => { + return ( +
+
+ {menu.map((link) => ( + + `block w-full p-4 text-center text-black outline-none transition-all dark:text-white ${isActive ? 'bg-orange-base text-white' : ''}` + } + > + {link.title} + + ))} +
+
+ +
+
+ ); +}; diff --git a/web/src/pages/ansible/docker/docker.tsx b/web/src/pages/ansible/docker/docker.tsx new file mode 100644 index 00000000..b10e5d50 --- /dev/null +++ b/web/src/pages/ansible/docker/docker.tsx @@ -0,0 +1,7 @@ +import { FC } from 'react'; + +const DockerAnsible: FC = () => { + return <>Docker; +}; + +export default DockerAnsible; diff --git a/web/src/pages/ansible/kuber/kuber.tsx b/web/src/pages/ansible/kuber/kuber.tsx new file mode 100644 index 00000000..df4d5f52 --- /dev/null +++ b/web/src/pages/ansible/kuber/kuber.tsx @@ -0,0 +1,7 @@ +import { FC } from 'react'; + +const KubernetesAnsible: FC = () => { + return <>Kubernetes; +}; + +export default KubernetesAnsible; diff --git a/web/src/pages/ansible/nginx/nginx.tsx b/web/src/pages/ansible/nginx/nginx.tsx new file mode 100644 index 00000000..3544aa8c --- /dev/null +++ b/web/src/pages/ansible/nginx/nginx.tsx @@ -0,0 +1,7 @@ +import { FC } from 'react'; + +const NginxAnsible: FC = () => { + return <>Nginx; +}; + +export default NginxAnsible; From cb19b79a3565bc6bf37981a20ef9917254e2b023 Mon Sep 17 00:00:00 2001 From: Milad Sadeghi Date: Wed, 4 Dec 2024 11:58:20 +0330 Subject: [PATCH 02/16] feat(web): Add download functionality to Ansible Template Docker service - Implemented download feature for Docker service in the Ansible Template section --- web/src/components/form/form-input.tsx | 24 +++- web/src/components/form/form-wrapper.tsx | 2 +- web/src/enums/api.enums.ts | 6 + .../docker/components/hosts-fields.tsx | 47 ++++++++ web/src/pages/ansible/docker/docker.tsx | 105 +++++++++++++++++- web/src/pages/ansible/docker/docker.types.ts | 38 +++++++ web/src/types/form.types.ts | 3 + 7 files changed, 218 insertions(+), 7 deletions(-) create mode 100644 web/src/pages/ansible/docker/components/hosts-fields.tsx create mode 100644 web/src/pages/ansible/docker/docker.types.ts diff --git a/web/src/components/form/form-input.tsx b/web/src/components/form/form-input.tsx index 50eb4c90..ed71c2c1 100644 --- a/web/src/components/form/form-input.tsx +++ b/web/src/components/form/form-input.tsx @@ -4,7 +4,15 @@ import { FormFieldProps } from '../../types/form.types'; import { getNestedValue } from '@/lib/helper'; import { cn } from '@/lib/utils'; -export const FormInput = ({ name, label, error, ...props }: FormFieldProps) => { +export const FormInput = ({ + name, + label, + error, + isNumber, + inputType, + inputClass, + ...props +}: FormFieldProps) => { const { register, formState: { errors }, @@ -21,14 +29,20 @@ export const FormInput = ({ name, label, error, ...props }: FormFieldProps) => { name={name} > {label && ( -
- {label} : +
+ {label}
)} diff --git a/web/src/components/form/form-wrapper.tsx b/web/src/components/form/form-wrapper.tsx index d3e92c95..a37eb225 100644 --- a/web/src/components/form/form-wrapper.tsx +++ b/web/src/components/form/form-wrapper.tsx @@ -16,7 +16,7 @@ export const FormWrapper = ({ methods, }: FormWrapperProps) => { return ( - + { + const { control } = useFormContext(); + + const { fields, append, remove } = useFieldArray({ + control, + name: 'hosts', + }); + + return ( +
+
+

Hosts

+ +
+
+ {fields.map((_, hostIdx) => ( +
+ + {hostIdx > 0 && ( + + )} +
+ ))} +
+
+ ); +}; + +export default HostsField; diff --git a/web/src/pages/ansible/docker/docker.tsx b/web/src/pages/ansible/docker/docker.tsx index b10e5d50..49c0b15f 100644 --- a/web/src/pages/ansible/docker/docker.tsx +++ b/web/src/pages/ansible/docker/docker.tsx @@ -1,7 +1,110 @@ import { FC } from 'react'; +import { + dockerAnsibleSchema, + type DockerAnsible, + type DockerAnsibleBody, + type DockerAnsibleResponse, + type dockerTemplateValidationError, +} from './docker.types'; +import { AnsibleTemplateAPI } from '@/enums/api.enums'; +import { useDownload } from '@/hooks'; +import { usePost } from '@/core/react-query'; +import { isAxiosError } from 'axios'; +import { toast } from 'sonner'; +import { useForm } from 'react-hook-form'; +import { zodResolver } from '@hookform/resolvers/zod'; +import { FormWrapper } from '@/components/form/form-wrapper'; +import { FormInput } from '@/components/form/form-input'; +import HostsField from './components/hosts-fields'; const DockerAnsible: FC = () => { - return <>Docker; + const defaultValues = { + ansible_user: '', + os: '', + hosts: [{ value: '' }], + }; + + const methods = useForm({ + resolver: zodResolver(dockerAnsibleSchema), + defaultValues, + }); + + const { mutateAsync: dockerAnsibleMutate, isPending: dockerAnsiblePending } = + usePost( + AnsibleTemplateAPI.Docker, + 'ansible-docker', + ); + + const { download, isPending: downloadPending } = useDownload({ + downloadFileName: '', + source: 'docker', + folderName: 'MyAnsible', + }); + + const handleSubmit = async (data: DockerAnsible) => { + try { + const body = { + ...data, + hosts: data.hosts.map((host) => host.value), + }; + + await dockerAnsibleMutate(body); + await download(); + } catch (error) { + console.log(error); + if (isAxiosError(error)) { + toast.error( + `${error.response?.data.detail[0].loc[error.response?.data.detail[0].loc.length - 1]} ${error.response?.data.detail[0].msg}`, + ); + } else { + toast.error('Something went wrong'); + } + } + }; + return ( +
+ +
+ +
+
+ +
+
+ +
+ + +
+
+ ); }; export default DockerAnsible; diff --git a/web/src/pages/ansible/docker/docker.types.ts b/web/src/pages/ansible/docker/docker.types.ts new file mode 100644 index 00000000..f80db60c --- /dev/null +++ b/web/src/pages/ansible/docker/docker.types.ts @@ -0,0 +1,38 @@ +import { z as zod } from 'zod'; + +export interface DockerAnsibleResponse { + output: string; +} + +export interface DockerAnsibleBody { + ansible_user?: string; + ansible_port: number; + os: string; + hosts: string[]; +} + +export interface dockerTemplateValidationError { + detail: [ + { + type: string; + loc: string[]; + msg: string; + input: null; + }, + ]; +} + +export const dockerAnsibleSchema = zod.object({ + ansible_user: zod.string().optional(), + ansible_port: zod.number({}), + os: zod.string().min(1, 'OS is required!'), + hosts: zod + .array( + zod.object({ + value: zod.string().min(1, 'Host is required!'), + }), + ) + .min(1), +}); + +export type DockerAnsible = zod.infer; diff --git a/web/src/types/form.types.ts b/web/src/types/form.types.ts index 26c29590..52f960de 100644 --- a/web/src/types/form.types.ts +++ b/web/src/types/form.types.ts @@ -8,6 +8,9 @@ export type FormFieldProps = { label: string; error?: string; placeholder?: string; + isNumber?: boolean; + inputType?: typeof HTMLInputElement.prototype.type; + inputClass?: string; } & ComponentPropsWithoutRef; export type FormConfig = { From 2cb9318b01a4a8d28cacf6b38b3262ce79c57baa Mon Sep 17 00:00:00 2001 From: Milad Sadeghi Date: Wed, 4 Dec 2024 14:12:41 +0330 Subject: [PATCH 03/16] refactor(web): Require all fields in Ansible Template Docker service form - Updated the design of select dropdowns and input fields --- web/src/components/form/form-input.tsx | 7 ++- web/src/components/form/form-select.tsx | 8 +-- .../docker/components/hosts-fields.tsx | 3 +- web/src/pages/ansible/docker/docker.tsx | 14 +++-- web/src/pages/ansible/docker/docker.types.ts | 13 +++-- web/src/styles/select.styles.ts | 55 +++++++++++++++++++ 6 files changed, 82 insertions(+), 18 deletions(-) create mode 100644 web/src/styles/select.styles.ts diff --git a/web/src/components/form/form-input.tsx b/web/src/components/form/form-input.tsx index ed71c2c1..be46e833 100644 --- a/web/src/components/form/form-input.tsx +++ b/web/src/components/form/form-input.tsx @@ -29,7 +29,7 @@ export const FormInput = ({ name={name} > {label && ( -
+
{label}
)} @@ -37,7 +37,8 @@ export const FormInput = ({ {errorMessage && (
- + {errorMessage}
diff --git a/web/src/components/form/form-select.tsx b/web/src/components/form/form-select.tsx index 25b0b513..2b89bcdd 100644 --- a/web/src/components/form/form-select.tsx +++ b/web/src/components/form/form-select.tsx @@ -4,9 +4,9 @@ import { Controller, useFormContext } from 'react-hook-form'; import { FormFieldProps } from '../../types/form.types'; import Select from 'react-select'; import { getNestedValue } from '@/lib/helper'; -import { selectStyle } from '@/pages/helm-template/styles/helm-template.style'; import { useStyle } from '@/hooks'; import { cn } from '@/lib/utils'; +import { selectStyle } from '@/styles/select.styles'; interface OptionType { value: string; @@ -46,8 +46,8 @@ export const FormSelect = ({ name={name} > {label && ( -
- {label} : +
+ {label}
)} @@ -68,7 +68,7 @@ export const FormSelect = ({ {errorMessage && (
- + {errorMessage}
diff --git a/web/src/pages/ansible/docker/components/hosts-fields.tsx b/web/src/pages/ansible/docker/components/hosts-fields.tsx index 876ea3d4..33e1f399 100644 --- a/web/src/pages/ansible/docker/components/hosts-fields.tsx +++ b/web/src/pages/ansible/docker/components/hosts-fields.tsx @@ -27,12 +27,11 @@ const HostsField: FC = () => { name={`hosts.${hostIdx}.value`} label="" placeholder="www.example.com" - className="w-full h-12 px-2 rounded-md outline-none" /> {hostIdx > 0 && ( diff --git a/web/src/pages/ansible/docker/docker.tsx b/web/src/pages/ansible/docker/docker.tsx index 49c0b15f..8a96180b 100644 --- a/web/src/pages/ansible/docker/docker.tsx +++ b/web/src/pages/ansible/docker/docker.tsx @@ -16,11 +16,13 @@ import { zodResolver } from '@hookform/resolvers/zod'; import { FormWrapper } from '@/components/form/form-wrapper'; import { FormInput } from '@/components/form/form-input'; import HostsField from './components/hosts-fields'; +import { FormSelect } from '@/components/form/form-select'; +import { OSOptions } from './data/select-options'; const DockerAnsible: FC = () => { const defaultValues = { ansible_user: '', - os: '', + os: { label: 'Ubuntu', value: 'ubuntu' }, hosts: [{ value: '' }], }; @@ -36,7 +38,7 @@ const DockerAnsible: FC = () => { ); const { download, isPending: downloadPending } = useDownload({ - downloadFileName: '', + downloadFileName: 'DockerAnsible', source: 'docker', folderName: 'MyAnsible', }); @@ -46,6 +48,7 @@ const DockerAnsible: FC = () => { const body = { ...data, hosts: data.hosts.map((host) => host.value), + os: data.os.value, }; await dockerAnsibleMutate(body); @@ -61,6 +64,7 @@ const DockerAnsible: FC = () => { } } }; + return (
@@ -83,11 +87,11 @@ const DockerAnsible: FC = () => { />
-
diff --git a/web/src/pages/ansible/docker/docker.types.ts b/web/src/pages/ansible/docker/docker.types.ts index f80db60c..d3767e7f 100644 --- a/web/src/pages/ansible/docker/docker.types.ts +++ b/web/src/pages/ansible/docker/docker.types.ts @@ -5,7 +5,7 @@ export interface DockerAnsibleResponse { } export interface DockerAnsibleBody { - ansible_user?: string; + ansible_user: string; ansible_port: number; os: string; hosts: string[]; @@ -23,9 +23,14 @@ export interface dockerTemplateValidationError { } export const dockerAnsibleSchema = zod.object({ - ansible_user: zod.string().optional(), - ansible_port: zod.number({}), - os: zod.string().min(1, 'OS is required!'), + ansible_user: zod.string().min(1, 'User is required!'), + ansible_port: zod + .number({ invalid_type_error: 'Port is required!' }) + .min(1, 'Port is required!'), + os: zod.object({ + label: zod.string(), + value: zod.string(), + }), hosts: zod .array( zod.object({ diff --git a/web/src/styles/select.styles.ts b/web/src/styles/select.styles.ts new file mode 100644 index 00000000..54f47fa9 --- /dev/null +++ b/web/src/styles/select.styles.ts @@ -0,0 +1,55 @@ +import { GroupBase, StylesConfig } from 'react-select'; + +export const selectStyle = ( + isDark?: boolean, +): + | StylesConfig< + { + label: string; + value: string; + }, + false, + GroupBase<{ + label: string; + value: string; + }> + > + | undefined => { + return { + control: (styles) => ({ + ...styles, + border: '1px solid #6b7280', + borderRadius: '6px', + background: isDark ? '#121212' : '#fff', + color: isDark ? '#fff' : '#121212', + height: '40px', + ':focus-within': { + border: 'none', + boxShadow: '0 0 0 1px #f86609', + }, + ':active': { + border: 'none', + }, + }), + menu: (styles) => ({ + ...styles, + background: isDark ? '#121212' : '#fff', + border: '1px solid #fff', + borderRadius: '6px', + boxShadow: '0 10px 10px 4px #000', + }), + + option: (styles) => ({ + ...styles, + background: isDark ? '#121212' : '#fff', + color: isDark ? '#fff' : '#121212', + ':hover': { + background: '#f86609', + }, + }), + singleValue: (styles) => ({ + ...styles, + color: isDark ? '#fff' : '#121212', + }), + }; +}; From 946da72cc23863263db80e8243511118aa278ee5 Mon Sep 17 00:00:00 2001 From: Milad Sadeghi Date: Wed, 4 Dec 2024 14:43:12 +0330 Subject: [PATCH 04/16] feat(web): Add download functionality to Ansible Template Kubernetes service --- .../kuber/components/k8s-master-nodes.tsx | 45 ++++++ .../kuber/components/k8s-worker-nodes.tsx | 45 ++++++ .../ansible/kuber/components/lb-nodes.tsx | 45 ++++++ web/src/pages/ansible/kuber/kuber.tsx | 132 +++++++++++++++++- web/src/pages/ansible/kuber/kuber.types.ts | 57 ++++++++ 5 files changed, 323 insertions(+), 1 deletion(-) create mode 100644 web/src/pages/ansible/kuber/components/k8s-master-nodes.tsx create mode 100644 web/src/pages/ansible/kuber/components/k8s-worker-nodes.tsx create mode 100644 web/src/pages/ansible/kuber/components/lb-nodes.tsx create mode 100644 web/src/pages/ansible/kuber/kuber.types.ts diff --git a/web/src/pages/ansible/kuber/components/k8s-master-nodes.tsx b/web/src/pages/ansible/kuber/components/k8s-master-nodes.tsx new file mode 100644 index 00000000..d5ff7230 --- /dev/null +++ b/web/src/pages/ansible/kuber/components/k8s-master-nodes.tsx @@ -0,0 +1,45 @@ +import { FormInput } from '@/components/form/form-input'; +import { Plus, Trash2 } from 'lucide-react'; +import { FC } from 'react'; +import { useFieldArray, useFormContext } from 'react-hook-form'; + +const K8SMasterNodes: FC = () => { + const { control } = useFormContext(); + + const { fields, append, remove } = useFieldArray({ + control, + name: 'k8s_master_nodes', + }); + + return ( +
+
+

K8s Master Nodes

+ +
+
+ {fields.map((_, nodeIdx) => ( +
+ + {nodeIdx > 0 && ( + + )} +
+ ))} +
+
+ ); +}; + +export default K8SMasterNodes; diff --git a/web/src/pages/ansible/kuber/components/k8s-worker-nodes.tsx b/web/src/pages/ansible/kuber/components/k8s-worker-nodes.tsx new file mode 100644 index 00000000..7c388b74 --- /dev/null +++ b/web/src/pages/ansible/kuber/components/k8s-worker-nodes.tsx @@ -0,0 +1,45 @@ +import { FormInput } from '@/components/form/form-input'; +import { Plus, Trash2 } from 'lucide-react'; +import { FC } from 'react'; +import { useFieldArray, useFormContext } from 'react-hook-form'; + +const K8SWorkerNodes: FC = () => { + const { control } = useFormContext(); + + const { fields, append, remove } = useFieldArray({ + control, + name: 'k8s_worker_nodes', + }); + + return ( +
+
+

K8s Worker Nodes

+ +
+
+ {fields.map((_, nodeIdx) => ( +
+ + {nodeIdx > 0 && ( + + )} +
+ ))} +
+
+ ); +}; + +export default K8SWorkerNodes; diff --git a/web/src/pages/ansible/kuber/components/lb-nodes.tsx b/web/src/pages/ansible/kuber/components/lb-nodes.tsx new file mode 100644 index 00000000..4da726e3 --- /dev/null +++ b/web/src/pages/ansible/kuber/components/lb-nodes.tsx @@ -0,0 +1,45 @@ +import { FormInput } from '@/components/form/form-input'; +import { Plus, Trash2 } from 'lucide-react'; +import { FC } from 'react'; +import { useFieldArray, useFormContext } from 'react-hook-form'; + +const LBNodes: FC = () => { + const { control } = useFormContext(); + + const { fields, append, remove } = useFieldArray({ + control, + name: 'lb_nodes', + }); + + return ( +
+
+

LB Nodes

+ +
+
+ {fields.map((_, nodeIdx) => ( +
+ + {nodeIdx > 0 && ( + + )} +
+ ))} +
+
+ ); +}; + +export default LBNodes; diff --git a/web/src/pages/ansible/kuber/kuber.tsx b/web/src/pages/ansible/kuber/kuber.tsx index df4d5f52..6b51865e 100644 --- a/web/src/pages/ansible/kuber/kuber.tsx +++ b/web/src/pages/ansible/kuber/kuber.tsx @@ -1,7 +1,137 @@ +import { zodResolver } from '@hookform/resolvers/zod'; import { FC } from 'react'; +import { useForm } from 'react-hook-form'; +import { + KuberAnsible, + KuberAnsibleBody, + KuberAnsibleResponse, + kuberAnsibleSchema, + kuberTemplateValidationError, +} from './kuber.types'; +import { FormWrapper } from '@/components/form/form-wrapper'; +import { FormInput } from '@/components/form/form-input'; +import { FormSelect } from '@/components/form/form-select'; +import { usePost } from '@/core/react-query'; +import { AnsibleTemplateAPI } from '@/enums/api.enums'; +import { OSOptions } from './data/select-options'; +import { useDownload } from '@/hooks'; +import { isAxiosError } from 'axios'; +import { toast } from 'sonner'; +import K8SMasterNodes from './components/k8s-master-nodes'; +import K8SWorkerNodes from './components/k8s-worker-nodes'; +import LBNodes from './components/lb-nodes'; const KubernetesAnsible: FC = () => { - return <>Kubernetes; + const { mutateAsync: kuberAnsibleMutate, isPending: kuberAnsiblePending } = + usePost( + AnsibleTemplateAPI.Kubernetes, + 'ansible-docker', + ); + + const { download, isPending: downloadPending } = useDownload({ + downloadFileName: 'KubernetesAnsible', + source: 'kubernetes', + folderName: 'MyAnsible', + }); + + const defaultValues = { + ansible_user: '', + os: { label: 'Ubuntu', value: 'ubuntu' }, + k8s_worker_nodes: [{ value: '' }], + k8s_master_nodes: [{ value: '' }], + lb_nodes: [{ value: '' }], + version: '', + }; + + const methods = useForm({ + resolver: zodResolver(kuberAnsibleSchema), + defaultValues, + }); + + const handleSubmit = async (data: KuberAnsible) => { + try { + const body = { + ...data, + k8s_worker_nodes: data.k8s_worker_nodes.map((worker) => worker.value), + k8s_master_nodes: data.k8s_master_nodes.map((master) => master.value), + lb_nodes: data.lb_nodes.map((lb) => lb.value), + os: data.os.value, + }; + + await kuberAnsibleMutate(body); + await download(); + } catch (error) { + console.log(error); + if (isAxiosError(error)) { + toast.error( + `${error.response?.data.detail[0].loc[error.response?.data.detail[0].loc.length - 1]} ${error.response?.data.detail[0].msg}`, + ); + } else { + toast.error('Something went wrong'); + } + } + }; + + return ( +
+ +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+ +
+
+ ); }; export default KubernetesAnsible; diff --git a/web/src/pages/ansible/kuber/kuber.types.ts b/web/src/pages/ansible/kuber/kuber.types.ts new file mode 100644 index 00000000..6373b2b4 --- /dev/null +++ b/web/src/pages/ansible/kuber/kuber.types.ts @@ -0,0 +1,57 @@ +import { z as zod } from 'zod'; + +export interface KuberAnsibleResponse { + output: string; +} + +export interface KuberAnsibleBody { + ansible_user: string; + ansible_port: number; + os: string; + k8s_worker_nodes: string[]; + k8s_master_nodes: string[]; + lb_nodes: string[]; + version: string; +} + +export interface kuberTemplateValidationError { + detail: [ + { + type: string; + loc: string[]; + msg: string; + input: null; + }, + ]; +} + +export const kuberAnsibleSchema = zod.object({ + ansible_user: zod.string().min(1, 'User is required!'), + ansible_port: zod + .number({ invalid_type_error: 'Port is required!' }) + .min(1, 'Port is required!'), + os: zod.object({ + label: zod.string(), + value: zod.string(), + }), + k8s_worker_nodes: zod + .array( + zod.object({ + value: zod.string().min(1, 'Required!'), + }), + ) + .min(1), + k8s_master_nodes: zod.array( + zod.object({ + value: zod.string().min(1, 'Required!'), + }), + ), + lb_nodes: zod.array( + zod.object({ + value: zod.string().min(1, 'Required!'), + }), + ), + version: zod.string().min(1, 'Version is required!'), +}); + +export type KuberAnsible = zod.infer; From 79d52abbbe9e5fc306c3131953504dd0098dce18 Mon Sep 17 00:00:00 2001 From: Milad Sadeghi Date: Wed, 4 Dec 2024 14:52:16 +0330 Subject: [PATCH 05/16] feat(web): Add download functionality to Ansible Template Nginx service --- .../ansible/nginx/components/hosts-field.tsx | 46 +++++++ web/src/pages/ansible/nginx/nginx.tsx | 120 +++++++++++++++++- web/src/pages/ansible/nginx/nginx.types.ts | 45 +++++++ 3 files changed, 210 insertions(+), 1 deletion(-) create mode 100644 web/src/pages/ansible/nginx/components/hosts-field.tsx create mode 100644 web/src/pages/ansible/nginx/nginx.types.ts diff --git a/web/src/pages/ansible/nginx/components/hosts-field.tsx b/web/src/pages/ansible/nginx/components/hosts-field.tsx new file mode 100644 index 00000000..33e1f399 --- /dev/null +++ b/web/src/pages/ansible/nginx/components/hosts-field.tsx @@ -0,0 +1,46 @@ +import { FormInput } from '@/components/form/form-input'; +import { Plus, Trash2 } from 'lucide-react'; +import { FC } from 'react'; +import { useFieldArray, useFormContext } from 'react-hook-form'; + +const HostsField: FC = () => { + const { control } = useFormContext(); + + const { fields, append, remove } = useFieldArray({ + control, + name: 'hosts', + }); + + return ( +
+
+

Hosts

+ +
+
+ {fields.map((_, hostIdx) => ( +
+ + {hostIdx > 0 && ( + + )} +
+ ))} +
+
+ ); +}; + +export default HostsField; diff --git a/web/src/pages/ansible/nginx/nginx.tsx b/web/src/pages/ansible/nginx/nginx.tsx index 3544aa8c..23f69fae 100644 --- a/web/src/pages/ansible/nginx/nginx.tsx +++ b/web/src/pages/ansible/nginx/nginx.tsx @@ -1,7 +1,125 @@ +import { zodResolver } from '@hookform/resolvers/zod'; import { FC } from 'react'; +import { useForm } from 'react-hook-form'; +import { + NginxAnsibleBody, + NginxAnsibleResponse, + nginxAnsibleSchema, + nginxTemplateValidationError, +} from './nginx.types'; +import { AnsibleTemplateAPI } from '@/enums/api.enums'; +import { usePost } from '@/core/react-query'; +import { useDownload } from '@/hooks'; +import { isAxiosError } from 'axios'; +import { toast } from 'sonner'; +import { FormWrapper } from '@/components/form/form-wrapper'; +import { FormInput } from '@/components/form/form-input'; +import { FormSelect } from '@/components/form/form-select'; +import HostsField from './components/hosts-field'; +import { OSOptions } from './data/select-options'; +import type { NginxAnsible } from './nginx.types'; const NginxAnsible: FC = () => { - return <>Nginx; + const defaultValues = { + ansible_user: '', + os: { label: 'Ubuntu', value: 'ubuntu' }, + hosts: [{ value: '' }], + version: '', + }; + + const methods = useForm({ + resolver: zodResolver(nginxAnsibleSchema), + defaultValues, + }); + + const { mutateAsync: nginxAnsibleMutate, isPending: nginxAnsiblePending } = + usePost( + AnsibleTemplateAPI.Nginx, + 'ansible-nginx', + ); + + const { download, isPending: downloadPending } = useDownload({ + downloadFileName: 'NginxAnsible', + source: 'nginx', + folderName: 'MyAnsible', + }); + + const handleSubmit = async (data: NginxAnsible) => { + try { + const body = { + ...data, + hosts: data.hosts.map((host) => host.value), + os: data.os.value, + }; + + await nginxAnsibleMutate(body); + await download(); + } catch (error) { + console.log(error); + if (isAxiosError(error)) { + toast.error( + `${error.response?.data.detail[0].loc[error.response?.data.detail[0].loc.length - 1]} ${error.response?.data.detail[0].msg}`, + ); + } else { + toast.error('Something went wrong'); + } + } + }; + + return ( +
+ +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+ +
+
+ ); }; export default NginxAnsible; diff --git a/web/src/pages/ansible/nginx/nginx.types.ts b/web/src/pages/ansible/nginx/nginx.types.ts new file mode 100644 index 00000000..0ba1f355 --- /dev/null +++ b/web/src/pages/ansible/nginx/nginx.types.ts @@ -0,0 +1,45 @@ +import { z as zod } from 'zod'; + +export interface NginxAnsibleResponse { + output: string; +} + +export interface NginxAnsibleBody { + ansible_user: string; + ansible_port: number; + os: string; + hosts: string[]; + version: string; +} + +export interface nginxTemplateValidationError { + detail: [ + { + type: string; + loc: string[]; + msg: string; + input: null; + }, + ]; +} + +export const nginxAnsibleSchema = zod.object({ + ansible_user: zod.string().min(1, 'User is required!'), + ansible_port: zod + .number({ invalid_type_error: 'Port is required!' }) + .min(1, 'Port is required!'), + os: zod.object({ + label: zod.string(), + value: zod.string(), + }), + hosts: zod + .array( + zod.object({ + value: zod.string().min(1, 'Host is required!'), + }), + ) + .min(1), + version: zod.string().min(1, 'Version is required!'), +}); + +export type NginxAnsible = zod.infer; From 76bbb72a7abfa16c4533780939c2518d5b4e5fa3 Mon Sep 17 00:00:00 2001 From: Milad Sadeghi Date: Wed, 4 Dec 2024 17:31:27 +0330 Subject: [PATCH 06/16] refactor(web): Fix Helm Template structure and styling issues - Refactored pod environment fields into separate components instead of defining them directly within the Helm Template --- .../components/pod-environment-fields.tsx | 68 +++++++++++++++ web/src/pages/helm-template/helm-template.tsx | 82 +++---------------- .../helm-template/helm-template.types.ts | 16 ++-- .../styles/helm-template.style.ts | 52 ------------ 4 files changed, 90 insertions(+), 128 deletions(-) create mode 100644 web/src/pages/helm-template/components/pod-environment-fields.tsx delete mode 100644 web/src/pages/helm-template/styles/helm-template.style.ts diff --git a/web/src/pages/helm-template/components/pod-environment-fields.tsx b/web/src/pages/helm-template/components/pod-environment-fields.tsx new file mode 100644 index 00000000..590a0174 --- /dev/null +++ b/web/src/pages/helm-template/components/pod-environment-fields.tsx @@ -0,0 +1,68 @@ +import { useFieldArray, useFormContext } from 'react-hook-form'; +import { Plus, Trash2 } from 'lucide-react'; +import { FormInput } from '@/components/form/form-input'; +import { cn } from '@/lib/utils'; +import { FC } from 'react'; + +type PodEnvironmentFieldsProps = { + podIndex: number; +}; + +const PodEnvironmentFields: FC = ({ podIndex }) => { + const { control } = useFormContext(); + const { fields, append, remove } = useFieldArray({ + control, + name: `pods.${podIndex}.environment`, + }); + + return ( +
+
+

Environments

+ + +
+
+ {fields.map((field, envIdx) => ( +
+ + + {envIdx > 0 && ( + + )} +
+ ))} +
+
+ ); +}; + +export default PodEnvironmentFields; diff --git a/web/src/pages/helm-template/helm-template.tsx b/web/src/pages/helm-template/helm-template.tsx index f008ef3d..007d1a61 100644 --- a/web/src/pages/helm-template/helm-template.tsx +++ b/web/src/pages/helm-template/helm-template.tsx @@ -6,7 +6,6 @@ import { API } from '@/enums/api.enums'; import { HelmTemplateBody, HelmTemplateResponse, - HelmTemplateSchema, helmTemplateSchema, helmTemplateValidationError, } from './helm-template.types'; @@ -14,13 +13,15 @@ import { toast } from 'sonner'; import { isAxiosError } from 'axios'; import { accessModesOptions, sizeOptions } from './data/select-options'; import { useDownload } from '@/hooks'; -import { useFieldArray, useForm, useFormContext } from 'react-hook-form'; +import { useFieldArray, useForm } from 'react-hook-form'; import { FormWrapper } from '@/components/form/form-wrapper'; import { zodResolver } from '@hookform/resolvers/zod'; import { FormInput } from '@/components/form/form-input'; import { FormCheckbox } from '@/components/form/form-checkbox'; import { FormSelect } from '@/components/form/form-select'; +import PodEnvironmentFields from './components/pod-environment-fields'; +import type { HelmTemplate } from './helm-template.types'; const HelmTemplate: FC = () => { const { mutateAsync: helmTemplateMutate, isPending: helmTemplatePending } = @@ -41,8 +42,7 @@ const HelmTemplate: FC = () => { { name: '', image: '', - target_port: null, - replicas: "", + replicas: '', persistance: {}, environment: [ { @@ -82,7 +82,7 @@ const HelmTemplate: FC = () => { remove(index); }; - const handleSubmit = async (data: HelmTemplateSchema) => { + const handleSubmit = async (data: HelmTemplate) => { try { const body_data = data.pods.map((data) => { const { mode, accessModes, size } = data.persistance; @@ -97,7 +97,7 @@ const HelmTemplate: FC = () => { }); const body: HelmTemplateBody = { - api_version: parseInt(data.api_version), + api_version: data.api_version, pods: body_data, }; @@ -125,6 +125,8 @@ const HelmTemplate: FC = () => { id="api_version" name="api_version" placeholder="2" + inputType="number" + isNumber={true} />
@@ -200,6 +202,8 @@ const HelmTemplate: FC = () => { name={`pods.${index}.target_port`} label="Target Port" placeholder="80" + inputType="number" + isNumber={true} />
@@ -208,6 +212,8 @@ const HelmTemplate: FC = () => { name={`pods.${index}.replicas`} label="Replicas" placeholder="1" + inputType="number" + isNumber={true} />

Persistence

@@ -219,7 +225,6 @@ const HelmTemplate: FC = () => { label="" placeholder="Value" /> - { }; export default HelmTemplate; - -interface PodEnvironmentFieldsProps { - podIndex: number; -} - -export const PodEnvironmentFields: React.FC = ({ - podIndex, -}) => { - const { control } = useFormContext(); - const { fields, append, remove } = useFieldArray({ - control, - name: `pods.${podIndex}.environment`, - }); - - return ( -
-
-

Environments

- - -
-
- {fields.map((field, envIdx) => ( -
- - - {envIdx > 0 && ( - - )} -
- ))} -
-
- ); -}; diff --git a/web/src/pages/helm-template/helm-template.types.ts b/web/src/pages/helm-template/helm-template.types.ts index e565cc07..93a02b2e 100644 --- a/web/src/pages/helm-template/helm-template.types.ts +++ b/web/src/pages/helm-template/helm-template.types.ts @@ -23,8 +23,6 @@ export interface helmTemplateValidationError { export interface Pod { name: string; image: string; - target_port: string | null; - replicas: string | null; persistance: { size: string; accessModes: string; @@ -65,8 +63,12 @@ const ingressSchema = zod.object({ const podSchema = zod.object({ name: zod.string().min(1, 'Name is required'), image: zod.string().min(1, 'Image is required'), - target_port: zod.string().nullable(), - replicas: zod.string().min(1 ,"Replicas is required"), + target_port: zod + .number({ invalid_type_error: 'Target Port is required!' }) + .min(1, 'Target Port is required!'), + replicas: zod + .number({ invalid_type_error: 'Replicas is required!' }) + .min(1, 'Replicas is required'), persistance: persistanceSchema, environment: zod .array(environmentSchema) @@ -76,7 +78,9 @@ const podSchema = zod.object({ }); export const helmTemplateSchema = zod.object({ - api_version: zod.string().min(1, 'API version is required'), + api_version: zod + .number({ invalid_type_error: 'API version is required!' }) + .min(1, 'API version is required'), pods: zod.array(podSchema).min(1, 'At least one pod is required'), }); -export type HelmTemplateSchema = zod.infer; +export type HelmTemplate = zod.infer; diff --git a/web/src/pages/helm-template/styles/helm-template.style.ts b/web/src/pages/helm-template/styles/helm-template.style.ts deleted file mode 100644 index bad06869..00000000 --- a/web/src/pages/helm-template/styles/helm-template.style.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { GroupBase, StylesConfig } from 'react-select'; - -export const selectStyle = ( - isDark?: boolean, -): - | StylesConfig< - { - label: string; - value: string; - }, - false, - GroupBase<{ - label: string; - value: string; - }> - > - | undefined => { - return { - control: (styles) => ({ - ...styles, - border: isDark ? 'none' : '1px solid #e3e3e3', - borderRadius: '6px', - background: isDark ? '#121212' : '#fff', - color: isDark ? '#fff' : '#121212', - height: '40px', - ':focus-within': { - border: 'none', - boxShadow: '0 0 0 1px #f86609', - }, - ':active': { - border: 'none', - }, - }), - menu: (styles) => ({ - ...styles, - background: isDark ? '#121212' : '#fff', - border: 'none', - }), - option: (styles) => ({ - ...styles, - background: isDark ? '#121212' : '#fff', - color: isDark ? '#fff' : '#121212', - ':hover': { - background: '#f86609', - }, - }), - singleValue: (styles) => ({ - ...styles, - color: isDark ? '#fff' : '#121212', - }), - }; -}; From f6e264ffad844a370d212b22936cce5b9027efb0 Mon Sep 17 00:00:00 2001 From: Milad Sadeghi Date: Wed, 4 Dec 2024 17:36:18 +0330 Subject: [PATCH 07/16] chore(web): Add missing data folders --- web/src/pages/ansible/docker/data/select-options.ts | 6 ++++++ web/src/pages/ansible/kuber/data/select-options.ts | 6 ++++++ web/src/pages/ansible/nginx/data/select-options.ts | 6 ++++++ web/src/pages/helm-template/helm-template.tsx | 4 ++-- web/src/pages/helm-template/helm-template.types.ts | 2 +- 5 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 web/src/pages/ansible/docker/data/select-options.ts create mode 100644 web/src/pages/ansible/kuber/data/select-options.ts create mode 100644 web/src/pages/ansible/nginx/data/select-options.ts diff --git a/web/src/pages/ansible/docker/data/select-options.ts b/web/src/pages/ansible/docker/data/select-options.ts new file mode 100644 index 00000000..aa31f9cd --- /dev/null +++ b/web/src/pages/ansible/docker/data/select-options.ts @@ -0,0 +1,6 @@ +export const OSOptions = [ + { + value: 'ubuntu', + label: 'Ubuntu', + }, +]; diff --git a/web/src/pages/ansible/kuber/data/select-options.ts b/web/src/pages/ansible/kuber/data/select-options.ts new file mode 100644 index 00000000..aa31f9cd --- /dev/null +++ b/web/src/pages/ansible/kuber/data/select-options.ts @@ -0,0 +1,6 @@ +export const OSOptions = [ + { + value: 'ubuntu', + label: 'Ubuntu', + }, +]; diff --git a/web/src/pages/ansible/nginx/data/select-options.ts b/web/src/pages/ansible/nginx/data/select-options.ts new file mode 100644 index 00000000..aa31f9cd --- /dev/null +++ b/web/src/pages/ansible/nginx/data/select-options.ts @@ -0,0 +1,6 @@ +export const OSOptions = [ + { + value: 'ubuntu', + label: 'Ubuntu', + }, +]; diff --git a/web/src/pages/helm-template/helm-template.tsx b/web/src/pages/helm-template/helm-template.tsx index 007d1a61..4ff61952 100644 --- a/web/src/pages/helm-template/helm-template.tsx +++ b/web/src/pages/helm-template/helm-template.tsx @@ -21,7 +21,7 @@ import { FormInput } from '@/components/form/form-input'; import { FormCheckbox } from '@/components/form/form-checkbox'; import { FormSelect } from '@/components/form/form-select'; import PodEnvironmentFields from './components/pod-environment-fields'; -import type { HelmTemplate } from './helm-template.types'; +import type { THelmTemplate } from './helm-template.types'; const HelmTemplate: FC = () => { const { mutateAsync: helmTemplateMutate, isPending: helmTemplatePending } = @@ -82,7 +82,7 @@ const HelmTemplate: FC = () => { remove(index); }; - const handleSubmit = async (data: HelmTemplate) => { + const handleSubmit = async (data: THelmTemplate) => { try { const body_data = data.pods.map((data) => { const { mode, accessModes, size } = data.persistance; diff --git a/web/src/pages/helm-template/helm-template.types.ts b/web/src/pages/helm-template/helm-template.types.ts index 93a02b2e..518b5d84 100644 --- a/web/src/pages/helm-template/helm-template.types.ts +++ b/web/src/pages/helm-template/helm-template.types.ts @@ -83,4 +83,4 @@ export const helmTemplateSchema = zod.object({ .min(1, 'API version is required'), pods: zod.array(podSchema).min(1, 'At least one pod is required'), }); -export type HelmTemplate = zod.infer; +export type THelmTemplate = zod.infer; From b9f0eb4d3105f68c790d3bf730fea912b9188639 Mon Sep 17 00:00:00 2001 From: Milad Sadeghi Date: Wed, 4 Dec 2024 18:43:41 +0330 Subject: [PATCH 08/16] refactor(web): Update `version` input to dropdown in Ansible Template Nginx service --- .../pages/ansible/nginx/data/select-options.ts | 7 +++++++ web/src/pages/ansible/nginx/nginx.tsx | 18 +++++++++++------- web/src/pages/ansible/nginx/nginx.types.ts | 5 ++++- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/web/src/pages/ansible/nginx/data/select-options.ts b/web/src/pages/ansible/nginx/data/select-options.ts index aa31f9cd..532a3294 100644 --- a/web/src/pages/ansible/nginx/data/select-options.ts +++ b/web/src/pages/ansible/nginx/data/select-options.ts @@ -4,3 +4,10 @@ export const OSOptions = [ label: 'Ubuntu', }, ]; + +export const VersionOptions = [ + { + value: 'latest', + label: 'Latest', + }, +]; diff --git a/web/src/pages/ansible/nginx/nginx.tsx b/web/src/pages/ansible/nginx/nginx.tsx index 23f69fae..0affb759 100644 --- a/web/src/pages/ansible/nginx/nginx.tsx +++ b/web/src/pages/ansible/nginx/nginx.tsx @@ -16,7 +16,7 @@ import { FormWrapper } from '@/components/form/form-wrapper'; import { FormInput } from '@/components/form/form-input'; import { FormSelect } from '@/components/form/form-select'; import HostsField from './components/hosts-field'; -import { OSOptions } from './data/select-options'; +import { OSOptions, VersionOptions } from './data/select-options'; import type { NginxAnsible } from './nginx.types'; const NginxAnsible: FC = () => { @@ -24,7 +24,10 @@ const NginxAnsible: FC = () => { ansible_user: '', os: { label: 'Ubuntu', value: 'ubuntu' }, hosts: [{ value: '' }], - version: '', + version: { + label: 'Latest', + value: 'latest', + }, }; const methods = useForm({ @@ -50,6 +53,7 @@ const NginxAnsible: FC = () => { ...data, hosts: data.hosts.map((host) => host.value), os: data.os.value, + version: data.version.value, }; await nginxAnsibleMutate(body); @@ -67,7 +71,7 @@ const NginxAnsible: FC = () => { }; return ( -
+
{
-
@@ -25,6 +25,7 @@ const K8SMasterNodes: FC = () => { {nodeIdx > 0 && ( diff --git a/web/src/pages/ansible/kuber/components/k8s-worker-nodes.tsx b/web/src/pages/ansible/kuber/components/k8s-worker-nodes.tsx index 7c388b74..3a7ee574 100644 --- a/web/src/pages/ansible/kuber/components/k8s-worker-nodes.tsx +++ b/web/src/pages/ansible/kuber/components/k8s-worker-nodes.tsx @@ -13,9 +13,9 @@ const K8SWorkerNodes: FC = () => { return (
-
+

K8s Worker Nodes

-
@@ -25,6 +25,7 @@ const K8SWorkerNodes: FC = () => { {nodeIdx > 0 && ( diff --git a/web/src/pages/ansible/kuber/components/lb-nodes.tsx b/web/src/pages/ansible/kuber/components/lb-nodes.tsx deleted file mode 100644 index 4da726e3..00000000 --- a/web/src/pages/ansible/kuber/components/lb-nodes.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import { FormInput } from '@/components/form/form-input'; -import { Plus, Trash2 } from 'lucide-react'; -import { FC } from 'react'; -import { useFieldArray, useFormContext } from 'react-hook-form'; - -const LBNodes: FC = () => { - const { control } = useFormContext(); - - const { fields, append, remove } = useFieldArray({ - control, - name: 'lb_nodes', - }); - - return ( -
-
-

LB Nodes

- -
-
- {fields.map((_, nodeIdx) => ( -
- - {nodeIdx > 0 && ( - - )} -
- ))} -
-
- ); -}; - -export default LBNodes; diff --git a/web/src/pages/ansible/kuber/data/select-options.ts b/web/src/pages/ansible/kuber/data/select-options.ts index 62f042ad..01c1cf70 100644 --- a/web/src/pages/ansible/kuber/data/select-options.ts +++ b/web/src/pages/ansible/kuber/data/select-options.ts @@ -6,6 +6,10 @@ export const OSOptions = [ ]; export const versionOptions = [ + { + label: '1.31', + value: '1.31', + }, { label: '1.30', value: '1.30', @@ -14,8 +18,4 @@ export const versionOptions = [ label: '1.29', value: '1.29', }, - { - label: '1.28', - value: '1.28', - }, ]; diff --git a/web/src/pages/ansible/kuber/kuber.tsx b/web/src/pages/ansible/kuber/kuber.tsx index 3db5ef6b..b76a06a8 100644 --- a/web/src/pages/ansible/kuber/kuber.tsx +++ b/web/src/pages/ansible/kuber/kuber.tsx @@ -19,7 +19,6 @@ import { isAxiosError } from 'axios'; import { toast } from 'sonner'; import K8SMasterNodes from './components/k8s-master-nodes'; import K8SWorkerNodes from './components/k8s-worker-nodes'; -import LBNodes from './components/lb-nodes'; const KubernetesAnsible: FC = () => { const { mutateAsync: kuberAnsibleMutate, isPending: kuberAnsiblePending } = @@ -39,7 +38,6 @@ const KubernetesAnsible: FC = () => { os: { label: 'Ubuntu', value: 'ubuntu' }, k8s_worker_nodes: [{ value: '' }], k8s_master_nodes: [{ value: '' }], - lb_nodes: [{ value: '' }], }; const methods = useForm({ @@ -53,7 +51,6 @@ const KubernetesAnsible: FC = () => { ...data, k8s_worker_nodes: data.k8s_worker_nodes.map((worker) => worker.value), k8s_master_nodes: data.k8s_master_nodes.map((master) => master.value), - lb_nodes: data.lb_nodes.map((lb) => lb.value), os: data.os.value, version: data.version.value, }; @@ -107,9 +104,6 @@ const KubernetesAnsible: FC = () => {
-
- -
Date: Wed, 4 Dec 2024 20:14:34 +0330 Subject: [PATCH 12/16] refactor(web): Reorder navbar links --- web/src/components/navbar/navbar.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/web/src/components/navbar/navbar.tsx b/web/src/components/navbar/navbar.tsx index 6c7ee758..25dbec08 100644 --- a/web/src/components/navbar/navbar.tsx +++ b/web/src/components/navbar/navbar.tsx @@ -11,14 +11,14 @@ const navbar = [ url: '/bug-fix', title: 'Bug Fix', }, - { - url: '/terraform-template', - title: 'Terraform Template', - }, { url: '/installation', title: 'Installation', }, + { + url: '/terraform-template', + title: 'Terraform Template', + }, { url: '/helm-template', title: 'Helm Template', From 644d7e4dd61315294e64efdbb3baca8f39741dcd Mon Sep 17 00:00:00 2001 From: Milad Sadeghi Date: Wed, 4 Dec 2024 20:16:55 +0330 Subject: [PATCH 13/16] chore(web): Rename argocd to `ArgoCD` across the application --- web/src/pages/terraform-template/ARGOCD/argocd.tsx | 2 +- web/src/pages/terraform-template/components/layout.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/web/src/pages/terraform-template/ARGOCD/argocd.tsx b/web/src/pages/terraform-template/ARGOCD/argocd.tsx index 7fc4b101..6bb0710e 100644 --- a/web/src/pages/terraform-template/ARGOCD/argocd.tsx +++ b/web/src/pages/terraform-template/ARGOCD/argocd.tsx @@ -138,7 +138,7 @@ const Argocd: FC = () => {
-

Argocd Repository

+

ArgoCD Repository

Date: Wed, 4 Dec 2024 20:38:13 +0330 Subject: [PATCH 14/16] style(web): Increase height of bug fix and basic page message box --- web/src/pages/basic/basic.tsx | 12 ++++++------ web/src/pages/bug-fix/bug-fix.tsx | 14 +++++++------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/web/src/pages/basic/basic.tsx b/web/src/pages/basic/basic.tsx index 5657b210..6d78b223 100644 --- a/web/src/pages/basic/basic.tsx +++ b/web/src/pages/basic/basic.tsx @@ -60,7 +60,7 @@ const Basic: FC = () => { return (
-
+
@@ -72,7 +72,7 @@ const Basic: FC = () => { type="number" value={minToken} onChange={(e) => setMinToken(e.target.value)} - className="dark:bg-black-1 w-full rounded-md bg-gray-200 p-3 outline-none" + className="w-full rounded-md bg-gray-200 p-3 outline-none dark:bg-black-1" />
@@ -84,7 +84,7 @@ const Basic: FC = () => { type="number" value={maxToken} onChange={(e) => setMaxToken(e.target.value)} - className="dark:bg-black-1 w-full rounded-md bg-gray-200 p-3 outline-none" + className="w-full rounded-md bg-gray-200 p-3 outline-none dark:bg-black-1" />
@@ -96,14 +96,14 @@ const Basic: FC = () => { type="text" value={service} onChange={(e) => setService(e.target.value)} - className="dark:bg-black-1 w-full rounded-md bg-gray-200 p-3 outline-none" + className="w-full rounded-md bg-gray-200 p-3 outline-none dark:bg-black-1" />
{messages.map((message) => message.role === 'user' ? ( @@ -131,7 +131,7 @@ const Basic: FC = () => { value={input} onChange={(e) => setInput(e.target.value)} rows={2} - className="dark:bg-black-1 w-full resize-none rounded-md bg-gray-200 p-4 pr-16 outline-none" + className="w-full resize-none rounded-md bg-gray-200 p-4 pr-16 outline-none dark:bg-black-1" />
- +
+ +
+
+ +