Skip to content
Closed

test #128

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
cfaf1e2
feat(docker-compose): add Docker Compose page with service management…
AmirhoseinBrz Dec 5, 2024
4c740f6
feat(docker-compose): update ServiceSchema to include name and change…
AmirhoseinBrz Dec 5, 2024
bcb7cc8
feat(web): merge with master
AmirhoseinBrz Dec 5, 2024
7148609
feat(web): add service management fields for dependencies, ports, vol…
AmirhoseinBrz Dec 5, 2024
42452a8
feat(web): add Docker Compose API endpoint and update form handling
AmirhoseinBrz Dec 5, 2024
d157717
feat(web): enhance service management with environment fields and val…
AmirhoseinBrz Dec 5, 2024
592105f
feat(web): rename PodEnvironmentFields to ServiceEnvironmentFields an…
AmirhoseinBrz Dec 5, 2024
ae4c282
feat(web): add utility functions for converting key-value pairs and s…
AmirhoseinBrz Dec 5, 2024
79f01e5
feat(web): expand DockerComposeBody interface with detailed service s…
AmirhoseinBrz Dec 5, 2024
92335a2
feat(web): add network management fields and validation schema to Doc…
AmirhoseinBrz Dec 5, 2024
e1eab64
feat(web): refactor Docker Compose handling and enhance network schem…
AmirhoseinBrz Dec 5, 2024
45d56b5
feat(web): integrate download functionality for Docker Compose files
AmirhoseinBrz Dec 5, 2024
ef1d6b1
feat(web): enhance network fields handling and improve validation mes…
AmirhoseinBrz Dec 5, 2024
90702f5
feat(web): refactor Docker Compose types and enhance network configur…
AmirhoseinBrz Dec 5, 2024
0525afb
feat(web): make build configuration optional in service config
AmirhoseinBrz Dec 5, 2024
cd86001
feat(web): remove console log from Docker Compose request handling
AmirhoseinBrz Dec 5, 2024
ec46140
feat(web): enhance service configuration handling and improve network…
AmirhoseinBrz Dec 5, 2024
2d8cfe0
refactor(web): remove unused watch from form select component
AmirhoseinBrz Dec 5, 2024
8aee3e9
refactor(web): Handle empty fields by sending null in Docker Compose
MiladSadeghi Dec 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions web/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ 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';
import DockerCompose from './pages/docker-compose/docker-compose';

function App() {
const location = useLocation();
Expand All @@ -27,6 +28,7 @@ function App() {
<Route index element={<Basic />} />
<Route path="bug-fix" element={<BugFix />} />
<Route path="helm-template" element={<HelmTemplate />} />
<Route path="docker-compose" element={<DockerCompose />} />
<Route path="terraform-template" element={<TerraformTemplate />}>
<Route path="docker" element={<Docker />} />
<Route path="ec2" element={<EC2 />} />
Expand Down
4 changes: 4 additions & 0 deletions web/src/components/navbar/navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ const navbar = [
url: '/helm-template',
title: 'Helm Template',
},
{
url: '/docker-compose',
title: 'Docker Compose',
},
{
url: '/ansible-template',
title: 'Ansible Template',
Expand Down
1 change: 1 addition & 0 deletions web/src/enums/api.enums.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export enum API {
BugFix = '/IaC-bugfix',
Installation = '/IaC-install',
HelmTemplate = '/Helm-template',
DockerCompose = "/docker-compose"
}

export enum AnsibleTemplateAPI {
Expand Down
33 changes: 33 additions & 0 deletions web/src/lib/helper.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,36 @@
import { IServiceConfig } from '@/pages/docker-compose/docker-compose.type';

export const getNestedValue = (obj: any, path: string) => {
return path.split('.').reduce((acc, part) => acc && acc[part], obj);
};

export const convertKVtoObject = (
kvArray: Array<{ key: string; value: string } | null>,
) => {
return kvArray?.reduce(
(acc, curr) => {

if (curr && acc) {
acc[curr.key] = curr?.value;

}
return acc;
},
{} as Record<string, string> | null,
);
};

interface Service {
name: string;
[key: string]: any;
}

export const convertServicesToObject = (
services: Service[],
): IServiceConfig => {
return services.reduce((acc, service) => {
const { name, ...serviceWithoutName } = service;
acc[name] = serviceWithoutName as IServiceConfig[string];
return acc;
}, {} as IServiceConfig);
};
116 changes: 116 additions & 0 deletions web/src/pages/docker-compose/components/network-fields.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import { FC } from 'react';
import { Plus, Trash2 } from 'lucide-react';
import { useFieldArray, useFormContext } from 'react-hook-form';
import { FormInput } from '@/components/form/form-input';
import { FormCheckbox } from '@/components/form/form-checkbox';
import { FormSelect } from '@/components/form/form-select';

const defaultNetworkDrivers = ['bridge', 'host', 'none', 'overlay'] as const;

const NetworkFields: FC = () => {
const { control, watch } = useFormContext();

const { fields, append, remove } = useFieldArray({
control,
name: 'networks.app_network',
});

const customNetwork = watch('networks.custom');

const handleRemoveNetwork = (index: number) => {
remove(index);
};

const handleAppendNetwork = () => {
const networkData = customNetwork
? {
network_name: '',
external: false,
name: '',
}
: {
network_name: '',
driver: {
label: 'bridge',
value: 'bridge',
},
};

append(networkData);
};

return (
<div>
<div className="mb-4 flex items-center justify-between">
<div className="flex items-center">
<p className="text-2xl font-bold">Networks</p>
<button
type="button"
onClick={handleAppendNetwork}
className="btn btn-xs ml-4"
>
Add <Plus className="size-3" />
</button>
</div>
<FormCheckbox label="Custom" name="networks.custom" />
</div>

<div className="space-y-4">
<div className="w-full rounded-md border border-gray-500 p-5">
{fields.map((field, index) => (
<div key={field.id} className="mb-4">
<div className="mb-4 flex items-center justify-between">
<p className="font-semibold">Network #{index + 1}</p>
{index > 0 && (
<button
type="button"
onClick={() => handleRemoveNetwork(index)}
>
<Trash2 className="size-4" color="red" />
</button>
)}
</div>

<div>
{customNetwork && (
<div className="mb-2 flex justify-end">
<FormCheckbox
name={`networks.app_network.${index}.external`}
label="External Network"
/>
</div>
)}
<div className="flex items-center gap-3 [&>div]:flex-1">
<FormInput
name={`networks.app_network.${index}.network_name`}
label="App Network"
placeholder="network_name"
/>
{!customNetwork && (
<FormSelect
name={`networks.app_network.${index}.driver`}
label="Network Driver"
options={defaultNetworkDrivers.map((driver) => ({
label: driver,
value: driver,
}))}
/>
)}
{customNetwork && (
<FormInput
name={`networks.app_network.${index}.name`}
label="Name"
placeholder="Name"
/>
)}
</div>
</div>
</div>
))}
</div>
</div>
</div>
);
};

export default NetworkFields;
101 changes: 101 additions & 0 deletions web/src/pages/docker-compose/components/service-build-fields.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import { FC } from 'react';
import { Plus, Trash2 } from 'lucide-react';
import { useFieldArray, useFormContext } from 'react-hook-form';
import { FormInput } from '@/components/form/form-input';
import { FormCheckbox } from '@/components/form/form-checkbox';
import { cn } from '@/lib/utils';

type ServiceBuildFieldsProps = {
serviceIndex: number;
};

export const ServiceBuildFields: FC<ServiceBuildFieldsProps> = ({
serviceIndex,
}) => {
const { control, watch } = useFormContext();
const buildEnabled = watch(`services.${serviceIndex}.build.enabled`);

const { fields, append, remove } = useFieldArray({
control,
name: `services.${serviceIndex}.build.args`,
});

return (
<div className="mb-2 mt-6">
<div className="mb-4 flex items-center justify-between">
<p className="text-base font-bold">Build Configuration</p>
<FormCheckbox
name={`services.${serviceIndex}.build.enabled`}
label="Enable Build"
/>
</div>

{buildEnabled && (
<div className="space-y-4 rounded-md border border-gray-200 p-4 dark:border-gray-500">
<div className="flex gap-2 [&>div]:flex-1">
<FormInput
name={`services.${serviceIndex}.build.context`}
label="Context"
placeholder="."
/>
<FormInput
name={`services.${serviceIndex}.build.dockerfile`}
label="Dockerfile"
placeholder="Dockerfile"
/>
</div>

<div className="space-y-2">
<div className="flex items-center">
<p className="text-sm font-semibold">Build Arguments</p>
<button
type="button"
onClick={() => append({ key: '', value: '' })}
className="btn btn-xs ml-4"
>
Add <Plus className="size-3" />
</button>
</div>

{fields.map((field, idx) => (
<div className="flex items-center" key={field.id}>
<div
className={cn(
'flex items-center divide-x divide-gray-200 rounded-md border border-gray-200 dark:divide-gray-500 dark:border-gray-500',
{
'divide-red-500 border-red-500 dark:divide-red-500 dark:border-red-500':
control.getFieldState(
`services.${serviceIndex}.volumes.${idx}`,
).invalid,
},
)}
key={field.id}
>
<FormInput
label=""
name={`services.${serviceIndex}.build.args.${idx}.key`}
placeholder="Key"
className="h-12 w-full rounded-s-md px-2"
/>
<FormInput
label=""
name={`services.${serviceIndex}.build.args.${idx}.value`}
placeholder="Value"
className="h-12 w-full rounded-e-md px-2"
/>
<button
type="button"
onClick={() => remove(idx)}
className="btn btn-error rounded-e-md rounded-s-none"
>
<Trash2 />
</button>
</div>
</div>
))}
</div>
</div>
)}
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { FC } from 'react';
import { Plus, Trash2 } from 'lucide-react';
import { useFieldArray, useFormContext } from 'react-hook-form';
import { FormInput } from '@/components/form/form-input';
import { cn } from '@/lib/utils';

type ServiceDependsOnFieldsProps = {
serviceIndex: number;
};

const ServiceDependsOnFields: FC<ServiceDependsOnFieldsProps> = ({
serviceIndex,
}) => {
const { control } = useFormContext();

const { fields, append, remove } = useFieldArray({
control,
name: `services.${serviceIndex}.depends_on`,
});

return (
<div className="mb-2 mt-6">
<div className="mb-2 flex items-center">
<p className="text-base font-bold">Depends On</p>

<button
type="button"
onClick={() => append('')}
className="btn btn-xs ml-4"
>
Add <Plus className="size-3" />
</button>
</div>
<div className="flex gap-4">
{fields.map((field, depIdx) => (
<div
className={cn(
'mb-4 flex items-center divide-x divide-gray-200 rounded-md border border-gray-200 dark:divide-gray-500 dark:border-gray-500 [&>div]:mb-0',
)}
key={field.id}
>
<FormInput
id={`depends_on_${depIdx}`}
name={`services.${serviceIndex}.depends_on.${depIdx}`}
label=""
placeholder="Service name"
className="h-12 w-full rounded-s-md px-2 outline-none"
/>

<button
onClick={() => remove(depIdx)}
className="btn btn-error rounded-e-md rounded-s-none"
>
<Trash2 />
</button>
</div>
))}
</div>
</div>
);
};

export default ServiceDependsOnFields;
Loading
Loading