-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
78 changed files
with
4,142 additions
and
772 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
75 changes: 75 additions & 0 deletions
75
dashboard/src/app/(authenticated)/(diagram)/components/Forms/components/BaseFormField.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import { Label } from '@/components/ui/label' | ||
import { FormFieldProp } from '@/types' | ||
import { CircleAlert } from 'lucide-react' | ||
import { FC, ReactNode } from 'react' | ||
import { useFormContext } from 'react-hook-form' | ||
import { accessLevels } from '../../../wfSpec/[...props]/components/Variables' | ||
import { Button } from '@/components/ui/button' | ||
|
||
type BaseFormFieldProps = FormFieldProp & { | ||
children: ReactNode | ||
isDisabled: boolean | ||
setIsDisabled: (disabled: boolean) => void | ||
} | ||
|
||
export const BaseFormField: FC<BaseFormFieldProps> = ({ | ||
variables, | ||
formState: { errors }, | ||
children, | ||
isDisabled, | ||
setIsDisabled, | ||
}) => { | ||
const { setValue, trigger } = useFormContext() | ||
|
||
if (!variables?.varDef?.name) return null | ||
|
||
const { | ||
varDef: { name }, | ||
required, | ||
accessLevel, | ||
} = variables | ||
|
||
const handleSetNull = () => { | ||
setValue(name, null) | ||
trigger(name) | ||
setIsDisabled(true) | ||
} | ||
|
||
const handleEnable = () => { | ||
setIsDisabled(false) | ||
} | ||
|
||
return ( | ||
<div> | ||
<div className="mb-2 flex justify-between"> | ||
<Label htmlFor={name} className="flex items-center gap-2"> | ||
{name} | ||
<span className="rounded bg-green-300 p-1 text-xs">{accessLevels[accessLevel]}</span> | ||
{required ? ( | ||
<span className="rounded bg-red-300 p-1 text-xs">Required</span> | ||
) : ( | ||
<span className="rounded bg-gray-300 p-1 text-xs">Optional</span> | ||
)} | ||
</Label> | ||
{!required && ( | ||
<Button | ||
type="button" | ||
variant="outline" | ||
size="sm" | ||
onClick={isDisabled ? handleEnable : handleSetNull} | ||
className="h-8" | ||
> | ||
{isDisabled ? 'Enter Value' : 'Set Null'} | ||
</Button> | ||
)} | ||
</div> | ||
{children} | ||
{errors[name] && ( | ||
<p className="mt-2 flex items-center gap-1 text-sm text-destructive"> | ||
<CircleAlert size={16} /> | ||
{errors[name]?.message} | ||
</p> | ||
)} | ||
</div> | ||
) | ||
} |
68 changes: 20 additions & 48 deletions
68
dashboard/src/app/(authenticated)/(diagram)/components/Forms/components/FormInput.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,77 +1,49 @@ | ||
import { VARIABLE_TYPES } from '@/app/constants' | ||
import { Input } from '@/components/ui/input' | ||
import { Label } from '@/components/ui/label' | ||
import { cn } from '@/components/utils' | ||
import { FormFieldProp } from '@/types' | ||
import { VariableType } from 'littlehorse-client/proto' | ||
import { CircleAlert } from 'lucide-react' | ||
import { FC, useState } from 'react' | ||
import { accessLevels } from '../../../wfSpec/[...props]/components/Variables' | ||
import { FC, useEffect, useState } from 'react' | ||
import { useFormContext } from 'react-hook-form' | ||
import { BaseFormField } from './BaseFormField' | ||
|
||
export const FormInput: FC<FormFieldProp> = props => { | ||
const [isDisabled, setIsDisabled] = useState(false) | ||
const [isDisabled, setIsDisabled] = useState(!props.variables?.required) | ||
const { setValue } = useFormContext() | ||
|
||
useEffect(() => { | ||
if (!props.variables?.required && props.variables?.varDef?.name) { | ||
setValue(props.variables.varDef.name, null) | ||
} | ||
}, [props.variables, setValue]) | ||
|
||
if (!props.variables?.varDef?.name) return null | ||
|
||
const { | ||
variables: { | ||
varDef: { type, name }, | ||
required, | ||
accessLevel, | ||
}, | ||
register, | ||
formState: { errors }, | ||
} = props | ||
|
||
const variableToType = (variable: VariableType) => { | ||
switch (variable) { | ||
case VariableType.INT: | ||
return 'number' | ||
case VariableType.DOUBLE: | ||
return 'number' | ||
case VariableType.BYTES: | ||
return 'number' | ||
case VariableType.STR: | ||
return 'text' | ||
default: | ||
return 'text' | ||
} | ||
} | ||
|
||
const setValue = (value: number | string) => { | ||
if (value === null) return value | ||
return variableToType(type) === 'number' ? parseFloat(value?.toString()) || undefined : value || undefined | ||
} | ||
|
||
return ( | ||
<div> | ||
<div className="mb-2 flex justify-between"> | ||
<Label htmlFor={name} className="flex items-center gap-2"> | ||
{name} | ||
<span className="rounded bg-green-300 p-1 text-xs">{accessLevels[accessLevel]}</span> | ||
{required ? ( | ||
<span className="rounded bg-red-300 p-1 text-xs">Required</span> | ||
) : ( | ||
<span className="rounded bg-gray-300 p-1 text-xs">Optional</span> | ||
)} | ||
</Label> | ||
</div> | ||
<BaseFormField {...props} isDisabled={isDisabled} setIsDisabled={setIsDisabled}> | ||
<Input | ||
type={variableToType(type)} | ||
className={errors[name] ? 'mb-1 mt-2 border-red-700' : 'mb-4 mt-1'} | ||
type={type === VariableType.INT || type === VariableType.DOUBLE ? 'number' : 'text'} | ||
className={cn(errors[name] && 'border-destructive')} | ||
id={name} | ||
step={type === VariableType.DOUBLE ? '0.01' : undefined} | ||
disabled={isDisabled} | ||
placeholder={`Enter ${VARIABLE_TYPES[type]?.toLowerCase()} value`} | ||
{...register(name, { | ||
required: required ? `${name} is required` : false, | ||
setValueAs: setValue, | ||
setValueAs: (value: string) => { | ||
return type === VariableType.INT || type === VariableType.DOUBLE ? parseFloat(value) || undefined : value | ||
}, | ||
})} | ||
/> | ||
{errors[name] && ( | ||
<p className="mb-3 flex items-center gap-1 text-sm text-red-700"> | ||
<CircleAlert size={16} /> | ||
{errors[name]?.message} | ||
</p> | ||
)} | ||
</div> | ||
</BaseFormField> | ||
) | ||
} |
55 changes: 16 additions & 39 deletions
55
dashboard/src/app/(authenticated)/(diagram)/components/Forms/components/FormSelect.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,76 +1,53 @@ | ||
import { Label } from '@/components/ui/label' | ||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' | ||
import { FormFieldProp } from '@/types' | ||
import { CircleAlert } from 'lucide-react' | ||
import { FC, useState } from 'react' | ||
import { FC, useEffect, useState } from 'react' | ||
import { useFormContext } from 'react-hook-form' | ||
import { accessLevels } from '../../../wfSpec/[...props]/components/Variables' | ||
import { BaseFormField } from './BaseFormField' | ||
import { cn } from '@/components/utils' | ||
|
||
export const FormSelect: FC<FormFieldProp> = props => { | ||
const { | ||
register, | ||
setValue, | ||
formState: { errors }, | ||
getValues, | ||
trigger, | ||
} = useFormContext() | ||
const [isDisabled, setIsDisabled] = useState(false) | ||
const [isDisabled, setIsDisabled] = useState(!props.variables?.required) | ||
const { register, setValue, getValues, trigger } = useFormContext() | ||
|
||
useEffect(() => { | ||
if (!props.variables?.required && props.variables?.varDef?.name) { | ||
setValue(props.variables.varDef.name, null) | ||
} | ||
}, [props.variables, setValue]) | ||
|
||
if (!props.variables?.varDef?.name) return null | ||
|
||
const { | ||
variables: { | ||
varDef: { name }, | ||
required, | ||
accessLevel, | ||
}, | ||
} = props | ||
|
||
const handleChange = (value: string) => { | ||
if (value === 'none') setValue(name, undefined) | ||
else { | ||
const booleanValue = value === 'true' | ||
setValue(name, booleanValue) | ||
} | ||
const booleanValue = value === 'true' | ||
setValue(name, booleanValue) | ||
trigger(name) | ||
} | ||
|
||
const value = getValues(name) | ||
|
||
return ( | ||
<div> | ||
<div className="mb-2 flex justify-between"> | ||
<Label htmlFor={name} className="center flex items-center gap-2"> | ||
{name} | ||
<span className="rounded bg-green-300 p-1 text-xs">{accessLevels[accessLevel]}</span> | ||
{required ? ( | ||
<span className="rounded bg-red-300 p-1 text-xs">Required</span> | ||
) : ( | ||
<span className="rounded bg-gray-300 p-1 text-xs">Optional</span> | ||
)} | ||
</Label> | ||
</div> | ||
<BaseFormField {...props} isDisabled={isDisabled} setIsDisabled={setIsDisabled}> | ||
<Select | ||
value={value?.toString() || ''} | ||
onValueChange={handleChange} | ||
disabled={isDisabled} | ||
{...register(name, { required: required ? `${name} is required` : false })} | ||
> | ||
<SelectTrigger id={name} className={errors[name] ? 'mb-1 mt-1 border-red-700' : 'mb-4 mt-1'}> | ||
<SelectTrigger id={name} className={cn(props.formState.errors[name] && 'border-destructive')}> | ||
<SelectValue placeholder="Select True or False" /> | ||
</SelectTrigger> | ||
<SelectContent> | ||
<SelectItem value="true">True</SelectItem> | ||
<SelectItem value="false">False</SelectItem> | ||
<SelectItem value="none">None</SelectItem> | ||
</SelectContent> | ||
</Select> | ||
{errors[name]?.message && ( | ||
<p className="mb-3 flex items-center gap-1 text-sm text-red-700"> | ||
<CircleAlert size={16} /> | ||
{String(errors[name]?.message)} | ||
</p> | ||
)} | ||
</div> | ||
</BaseFormField> | ||
) | ||
} |
46 changes: 16 additions & 30 deletions
46
dashboard/src/app/(authenticated)/(diagram)/components/Forms/components/FormTextarea.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,63 +1,49 @@ | ||
import { Label } from '@/components/ui/label' | ||
import { VARIABLE_TYPES } from '@/app/constants' | ||
import { Textarea } from '@/components/ui/textarea' | ||
import { cn } from '@/components/utils' | ||
import { FormFieldProp } from '@/types' | ||
import { FC, useState } from 'react' | ||
|
||
import { VARIABLE_TYPES } from '@/app/constants' | ||
import { CircleAlert } from 'lucide-react' | ||
import { FC, useEffect, useState } from 'react' | ||
import { useFormContext } from 'react-hook-form' | ||
import { accessLevels } from '../../../wfSpec/[...props]/components/Variables' | ||
import { BaseFormField } from './BaseFormField' | ||
import { getValidation } from './validation' | ||
|
||
export const FormTextarea: FC<FormFieldProp> = props => { | ||
const [isDisabled, setIsDisabled] = useState(false) | ||
const [isDisabled, setIsDisabled] = useState(!props.variables?.required) | ||
const { setValue, trigger } = useFormContext() | ||
|
||
if (!props.variables?.varDef?.name) return | ||
useEffect(() => { | ||
if (!props.variables?.required && props.variables?.varDef?.name) { | ||
setValue(props.variables.varDef.name, null) | ||
} | ||
}, [props.variables, setValue]) | ||
|
||
if (!props.variables?.varDef?.name) return null | ||
const { | ||
variables: { | ||
varDef: { type, name }, | ||
accessLevel, | ||
required, | ||
}, | ||
register, | ||
formState: { errors }, | ||
} = props | ||
|
||
return ( | ||
<div> | ||
<div className="flex justify-between"> | ||
<Label htmlFor={name} className="flex items-center gap-2"> | ||
{name} | ||
<span className="rounded bg-green-300 p-1 text-xs">{accessLevels[accessLevel]}</span> | ||
{required ? ( | ||
<span className="rounded bg-red-300 p-1 text-xs">Required</span> | ||
) : ( | ||
<span className="rounded bg-gray-300 p-1 text-xs">Optional</span> | ||
)} | ||
</Label> | ||
</div> | ||
<BaseFormField {...props} isDisabled={isDisabled} setIsDisabled={setIsDisabled}> | ||
<Textarea | ||
className={errors[name] ? 'mb-1 mt-1 min-h-[120px] border-red-700' : 'mb-4 mt-1 rounded-xl'} | ||
className={cn(errors[name] && 'border-destructive')} | ||
id={name} | ||
disabled={isDisabled} | ||
placeholder={`Enter ${VARIABLE_TYPES[type]?.toLowerCase()} value`} | ||
{...register(name, { | ||
required: required ? `${name} is required` : false, | ||
validate: getValidation(type), | ||
onChange: e => { | ||
setValue(name, e.target.value || undefined) | ||
setValue(name, e.target.value) | ||
trigger(name) | ||
}, | ||
})} | ||
defaultValue="" | ||
/> | ||
{errors[name] && ( | ||
<p className="mb-3 flex items-center gap-1 text-sm text-red-700"> | ||
<CircleAlert size={16} /> | ||
{errors[name]?.message} | ||
</p> | ||
)} | ||
</div> | ||
</BaseFormField> | ||
) | ||
} |
Oops, something went wrong.