Skip to content

Commit

Permalink
feat/services-logic (#133)
Browse files Browse the repository at this point in the history
* feat(context): adding interface

* feat(context): adding interface

* feat(context): adding form

* feat(context): adding form

* feat(context): adding form
  • Loading branch information
JyTosTT authored Oct 10, 2023
1 parent c8f6cd4 commit 0a86de8
Show file tree
Hide file tree
Showing 12 changed files with 222 additions and 16 deletions.
18 changes: 6 additions & 12 deletions front/src/forms/editor.structure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import TextArea from '../views/atoms/forms/TextArea.atom'
import EnvVariablesOrganism from '../views/organisms/ServiceVariables/EnvVariables.organism'
import PortVariablesOrganism from '../views/organisms/ServiceVariables/PortVariables.organism'
import VolumeVariablesOrganism from '../views/organisms/ServiceVariables/VolumeVariables.organism'
import LocalisationFormOrganism from '../views/organisms/ServiceForm/LocalisationForm.organism'

export type EditorStructure = {
[key in DrawerTypes]: EditorForm[]
Expand All @@ -27,6 +28,7 @@ export interface EditorForm {
type: TypeList
component: any

disabled?: any
validator?: any
maxLength?: number
}
Expand Down Expand Up @@ -111,18 +113,10 @@ export const DRAWER_TYPE_STRUCTURES: EditorStructure = {
maxLength: 25
},
{
label: 'Docker Image',
key: 'dockerImage',
type: TypeList.TEXT,
component: Input,
validator: string().nullable()
},
{
label: 'Docker Tag',
key: 'dockerTag',
type: TypeList.TEXT,
component: Input,
validator: string().nullable()
label: 'Context',
key: 'context',
type: TypeList.CUSTOM,
component: LocalisationFormOrganism
},
{
label: 'Env file',
Expand Down
1 change: 1 addition & 0 deletions front/src/hooks/useDrawerEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ const useDrawerEditor = (drawer: TDrawer, stackId: string): TEditor<TEntity> =>
return {
fields: structure,
entityForm,
onForm: setEntityForm,
onSubmit,
onChange,
onDelete,
Expand Down
1 change: 1 addition & 0 deletions front/src/hooks/useLinkerEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ const useDrawerEditor = (linker: TBaseLinker, _: string): TEditor<TLinkEntity> =
fields: structure,
entityForm: linkerForm,
onSubmit,
onForm: setLinkerForm,
onDelete,
onChange,
onClose
Expand Down
1 change: 1 addition & 0 deletions front/src/interfaces/Forms/Input.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export interface InputProps {
className?: string
required?: boolean
maxLength?: number
disabled?: boolean
onChange?: (e: TOnChange) => void
onKeyDown?: (e: React.KeyboardEvent<HTMLInputElement>) => void
}
Expand Down
4 changes: 4 additions & 0 deletions front/src/interfaces/Service.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@ export interface IService {

name: string
description: string
containerName: string
dockerImage: string
dockerTag: string
entrypoint: string

isExternal: boolean

context: string
dockerFile: string

positionX: number
positionY: number
test: number
Expand Down
2 changes: 2 additions & 0 deletions front/src/types/board/drawer/Common.bases.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { type EditorForm } from '../../../forms/editor.structure'
import { type TOnChange } from '../../../interfaces/Forms/Input.interface'
import { type IForm } from '../../../hooks/useForm'

export interface TCommonBases {
create: () => void
Expand All @@ -12,5 +13,6 @@ export interface TEditor<T> {
onChange: (event: TOnChange) => void
onDelete?: () => void
onClose: () => void
onForm: IForm<T>['setForm']
entityForm: T
}
3 changes: 2 additions & 1 deletion front/src/views/atoms/forms/Input.atom.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react'
import { type InputProps } from '../../../interfaces/Forms/Input.interface'

const Input = ({ label, type, placeholder, name, value, className = '', onChange, onKeyDown, maxLength, required = false }: InputProps): JSX.Element => {
const Input = ({ label, type, placeholder, name, value, className = '', onChange, onKeyDown, maxLength, required = false, disabled }: InputProps): JSX.Element => {
return (
<>
{(label != null) && <label className="font-semibold text-sm text-gray-600 pb-1 block">{label}</label> }
Expand All @@ -13,6 +13,7 @@ const Input = ({ label, type, placeholder, name, value, className = '', onChange
onChange={onChange}
onKeyDown={onKeyDown}
maxLength={maxLength}
disabled={disabled}
className={`input input-bordered w-full max-w-xs mt-1 ${className}`}
required={required}
/>
Expand Down
22 changes: 22 additions & 0 deletions front/src/views/atoms/forms/RadioButton.atom.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from 'react'
import { type CheckboxProps } from '../../../interfaces/Forms/Checkbox.interface'

const Radio = ({ label, name, value = false, className = '', onChange, onKeyDown }: CheckboxProps): JSX.Element => {
return (
<label className={`label cursor-pointer ${className}`} style={{ justifyContent: 'unset', gap: '10px' }}>
<input
type="radio"
name={name}
checked={value}
className={'radio'}
onChange={onChange}
onKeyDown={onKeyDown}
/>
<span className="label-text">
{label}
</span>
</label>
)
}

export default Radio
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react'
import VariableMolecule from './Variable.molecule'
import { type IServicePortVariable, type IServicePortVariableCreate } from '../../../interfaces/ServiceVariable/Port.interface'
import { type IVariableMolecule } from '../../../hooks/ServiceVariables/useEnvVariablesEditor'
import { type IVariableMolecule } from '../../../interfaces/VariableConfig.interface'

const PortVariableMolecule = (props: IVariableMolecule<IServicePortVariableCreate, IServicePortVariable>): JSX.Element => {
return <VariableMolecule<IServicePortVariable, IServicePortVariableCreate> {...props} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ IVariableMolecule<IVariableCreate, IVariable>): JSX.Element {
const defaultByType = {
[TypeList.TEXT]: '',
[TypeList.NUMBER]: 0,
[TypeList.CUSTOM]: undefined
[TypeList.CUSTOM]: undefined,
[TypeList.CHECKBOX]: undefined,
[TypeList.FILE]: undefined
}

const keyList = fields.map(({ key, type }) => ({ [key]: defaultByType[type] }))
Expand Down
12 changes: 11 additions & 1 deletion front/src/views/organisms/Editor.organism.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,15 @@ const EditorOrganism = ({ entity, stackId, useEditor }: {
stackId: string
useEditor: typeof useDrawerEditor | typeof useLinkerEditor
}): JSX.Element => {
const { fields, onSubmit, onChange, entityForm, onDelete, onClose } = useEditor(entity, stackId)
const {
fields,
onSubmit,
onChange,
entityForm,
onForm,
onDelete,
onClose
} = useEditor(entity, stackId)

return (
<div className="w-full border-l-2 bg-white h-full max-h-full overflow-y-auto">
Expand Down Expand Up @@ -39,7 +47,9 @@ const EditorOrganism = ({ entity, stackId, useEditor }: {
type={field.type}
name={field.key}
maxLength={field.maxLength}
entityForm={entityForm}
entity={entity}
onForm={onForm}
value={value}
onChange={onChange}
/>
Expand Down
168 changes: 168 additions & 0 deletions front/src/views/organisms/ServiceForm/LocalisationForm.organism.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
import React, { type ChangeEvent } from 'react'
import Input from '../../atoms/forms/Input.atom'
import { type IService } from '../../../interfaces/Service.interface'
import { type TEditor } from '../../../types/board/drawer/Common.bases'
import { type TEntity } from '../../../types/Entity'
import { type EditorForm, TypeList } from '../../../forms/editor.structure'
import { string } from 'yup'
import Radio from '../../atoms/forms/RadioButton.atom'
import useToggle from '../../../hooks/useToggle'
import { Errors } from '../../../enums/errors'

const isDefined = (value: string): boolean =>
value !== undefined && value !== null && value !== ''

const keys = (fields: EditorForm[]): string[] => fields.map((field) => field.key)

const LOCAL_RADIO_NAME: string = 'local'
const REMOTE_RADIO_NAME: string = 'remote'

const LocalisationFormOrganism = ({ entityForm: serviceForm, onChange, onForm }: {
entityForm: IService
onChange: TEditor<TEntity>['onChange']
onForm: TEditor<TEntity>['onForm']
}): JSX.Element => {
const [hasSelectedRemote, toggleSelectedRemote] = useToggle(
isDefined(serviceForm.dockerImage) && isDefined(serviceForm.dockerTag)
)

const [hasSelectedLocal, toggleSelectedLocal] = useToggle(
isDefined(serviceForm.context) && isDefined(serviceForm.dockerFile)
)

const isEmptyFields = !hasSelectedRemote && !hasSelectedLocal

const remoteFieldsDisabled = hasSelectedLocal || isEmptyFields
const REMOTE_FIELDS: EditorForm[] = [
{
label: 'Docker image',
key: 'dockerImage',
type: TypeList.TEXT,
component: Input,
validator: string().nullable(),
disabled: remoteFieldsDisabled
},
{
label: 'Docker tag',
key: 'dockerTag',
type: TypeList.TEXT,
component: Input,
validator: string().nullable(),
disabled: remoteFieldsDisabled
}
]

const localFieldsDisabled = hasSelectedRemote || isEmptyFields
const LOCAL_FIELDS: EditorForm[] = [
{
label: 'Context',
key: 'context',
type: TypeList.TEXT,
component: Input,
validator: string().nullable(),
disabled: localFieldsDisabled
},
{
label: 'Docker file',
key: 'dockerFile',
type: TypeList.TEXT,
component: Input,
validator: string().nullable(),
disabled: localFieldsDisabled
}
]

const LOCALISATION_FIELDS: EditorForm[][] = [
REMOTE_FIELDS,
LOCAL_FIELDS
]

const onKeyFormReset = (key: keyof TEntity): void => {
// @ts-expect-error ts-migrate Object is possibly 'undefined'.
serviceForm[key] = ''
}

const emptyFieldsRadioSelection = (name: string): void => {
if (name === 'local') {
toggleSelectedLocal()
} else if (name === 'remote') {
toggleSelectedRemote()
} else {
throw new Error(Errors.NOT_IMPLEMENTED)
}
}

const onEntityRadioChange = (name: string): void => {
if (name === 'local') {
keys(REMOTE_FIELDS).forEach((key) => {
onKeyFormReset(key as keyof TEntity)
})
} else if (name === 'remote') {
keys(LOCAL_FIELDS).forEach((key) => {
onKeyFormReset(key as keyof TEntity)
})
} else {
throw new Error(Errors.NOT_IMPLEMENTED)
}

toggleSelectedRemote()
toggleSelectedLocal()
onForm({ ...serviceForm })
}

const onRadioChange = (event: ChangeEvent<HTMLInputElement>): void => {
const { name, value } = event.target

if (value !== 'on') return

if (isEmptyFields) {
emptyFieldsRadioSelection(name)
} else {
onEntityRadioChange(name)
}
}

const generateFields = (fields: EditorForm[]): JSX.Element[] => {
return fields.map((field, index) => {
const Component = field.component
const value = serviceForm[field.key as keyof TEntity]

return (
<Component
label={field.label}
type={field.type}
name={field.key}
maxLength={field.maxLength}
entity={serviceForm}
value={value}
disabled={field.disabled}
onChange={onChange}
key={index}
/>)
})
}

return (
<div className="container mx-auto">
<div className="flex flex-wrap -mx-2 p-2 ">
<div className="w-1/2">
<Radio label="Remote" value={hasSelectedRemote} onChange={onRadioChange} name={REMOTE_RADIO_NAME}/>
</div>
<div className="w-1/2">
<Radio label="Local" value={hasSelectedLocal} onChange={onRadioChange} name={LOCAL_RADIO_NAME}/>
</div>

{LOCALISATION_FIELDS.map((editor, index) => {
return (
<div className="w-1/2 flex items-center" key={index}>
<div className="mr-1">
{generateFields(editor)}
</div>
</div>)
})}
</div>
</div>
)
}

export default LocalisationFormOrganism

0 comments on commit 0a86de8

Please sign in to comment.