Skip to content

Commit 7dfb823

Browse files
authored
Merge pull request #300 from devtron-labs/feat/useForm-hook
feat: useForm - form handling hook
2 parents 600429e + a9a9e74 commit 7dfb823

File tree

13 files changed

+411
-118
lines changed

13 files changed

+411
-118
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@devtron-labs/devtron-fe-common-lib",
3-
"version": "0.3.11",
3+
"version": "0.3.12",
44
"description": "Supporting common component library",
55
"type": "module",
66
"main": "dist/index.js",

src/Common/CustomInput/CustomInput.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export const CustomInput = ({
3737
rootClassName = '',
3838
autoComplete = 'off',
3939
helperText = '',
40-
handleOnBlur,
40+
onBlur,
4141
readOnly = false,
4242
noTrim = false,
4343
onKeyPress,
@@ -66,15 +66,15 @@ export const CustomInput = ({
6666
return error
6767
}
6868

69-
const onBlur = (event) => {
69+
const handleOnBlur = (event) => {
7070
// NOTE: This is to prevent the input from being trimmed when the user do not want to trim the input
7171
if (!noTrim) {
7272
event.stopPropagation()
7373
event.target.value = event.target.value?.trim()
7474
onChange(event)
7575
}
76-
if (typeof handleOnBlur === 'function') {
77-
handleOnBlur(event)
76+
if (typeof onBlur === 'function') {
77+
onBlur(event)
7878
}
7979
}
8080

@@ -127,7 +127,7 @@ export const CustomInput = ({
127127
e.persist()
128128
onChange(e)
129129
}}
130-
onBlur={onBlur}
130+
onBlur={handleOnBlur}
131131
onFocus={onFocus}
132132
placeholder={placeholder}
133133
value={value}

src/Common/CustomInput/Types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export interface CustomInputProps {
3434
rootClassName?: string
3535
error?: string[] | string
3636
helperText?: ReactNode
37-
handleOnBlur?: (e) => void
37+
onBlur?: (e) => void
3838
readOnly?: boolean
3939
noTrim?: boolean
4040
onKeyPress?: (e) => void

src/Common/CustomTagSelector/TagDetails.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export const TagDetails = ({
6060
{!hidePropagateTag && (
6161
<div
6262
className={`dc__border h-30 pl-4 pr-4 br-4 mr-8 pointer ${tagData.propagate ? 'bcn-7' : ''} ${tagData.key.startsWith('devtron.ai/') ? 'cursor-not-allowed bcn-1' : ''}`}
63-
onClick={propagateTagToResource}
63+
onClick={!tagData?.isPropagateDisabled ? propagateTagToResource : null}
6464
data-testid={`propagate-tag-${index}`}
6565
>
6666
<InjectTag className={`icon-dim-20 mt-4 ${tagData.propagate ? 'scn-0' : ''}`} />

src/Common/DeleteComponentModal/DeleteComponent.tsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,14 @@
1414
* limitations under the License.
1515
*/
1616

17-
import React, { useState } from 'react'
17+
import { useState } from 'react'
1818
import { useHistory } from 'react-router-dom'
1919
import info from '../../Assets/Icon/ic-info-filled.svg'
2020
import { ConfirmationDialog, DeleteDialog } from '../Dialogs'
2121
import { ServerErrors } from '../ServerError'
2222
import { DeleteComponentProps } from './types'
2323
import { ToastManager, ToastVariantType } from '@Shared/Services'
24+
import { showError } from '@Common/Helper'
2425

2526
const DeleteComponent = ({
2627
setDeleting,
@@ -36,11 +37,13 @@ const DeleteComponent = ({
3637
configuration = '',
3738
closeCustomComponent,
3839
}: DeleteComponentProps) => {
40+
const [isDeleting, setIsDeleting] = useState(false)
3941
const [showCannotDeleteDialogModal, setCannotDeleteDialogModal] = useState(false)
4042
const { push } = useHistory()
4143

4244
async function handleDelete() {
43-
setDeleting(true)
45+
setDeleting?.(true)
46+
setIsDeleting(true)
4447
try {
4548
await deleteComponent(payload)
4649
ToastManager.showToast({
@@ -59,9 +62,12 @@ const DeleteComponent = ({
5962
} catch (serverError) {
6063
if (serverError instanceof ServerErrors && serverError.code === 500) {
6164
setCannotDeleteDialogModal(true)
65+
} else {
66+
showError(serverError)
6267
}
6368
} finally {
64-
setDeleting(false)
69+
setDeleting?.(false)
70+
setIsDeleting(false)
6571
}
6672
}
6773

@@ -92,6 +98,7 @@ const DeleteComponent = ({
9298
delete={handleDelete}
9399
closeDelete={() => toggleConfirmation(false)}
94100
dataTestId="delete-dialog"
101+
apiCallInProgress={isDeleting}
95102
>
96103
<DeleteDialog.Description>
97104
<p>Are you sure you want to delete this {configuration || component}? </p>

src/Common/DeleteComponentModal/types.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@
1515
*/
1616

1717
export interface DeleteComponentProps {
18-
setDeleting: (boolean) => void
18+
/**
19+
* @deprecated - Delete component internally handles loading for the `Delete Button`.
20+
*/
21+
setDeleting?: (boolean) => void
1922
toggleConfirmation: any
2023
deleteComponent: (any) => Promise<any>
2124
title: string

src/Common/Helper.tsx

Lines changed: 0 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -206,110 +206,6 @@ export function getCookie(sKey) {
206206
)
207207
}
208208

209-
export function useForm(stateSchema, validationSchema = {}, callback) {
210-
const [state, setState] = useState(stateSchema)
211-
const [disable, setDisable] = useState(true)
212-
const [isDirty, setIsDirty] = useState(false)
213-
214-
// Disable button in initial render.
215-
useEffect(() => {
216-
setDisable(true)
217-
}, [])
218-
219-
// For every changed in our state this will be fired
220-
// To be able to disable the button
221-
useEffect(() => {
222-
if (isDirty) {
223-
setDisable(validateState(state))
224-
}
225-
}, [state, isDirty])
226-
227-
// Used to disable submit button if there's an error in state
228-
// or the required field in state has no value.
229-
// Wrapped in useCallback to cached the function to avoid intensive memory leaked
230-
// in every re-render in component
231-
const validateState = useCallback(
232-
(state) => {
233-
// check errors in all fields
234-
const hasErrorInState = Object.keys(validationSchema).some((key) => {
235-
const isInputFieldRequired = validationSchema[key].required
236-
const stateValue = state[key].value // state value
237-
const stateError = state[key].error // state error
238-
return (isInputFieldRequired && !stateValue) || stateError
239-
})
240-
return hasErrorInState
241-
},
242-
[state, validationSchema],
243-
)
244-
245-
function validateField(name, value): string | string[] {
246-
if (validationSchema[name].required) {
247-
if (!value) {
248-
return 'This is a required field.'
249-
}
250-
}
251-
252-
function _validateSingleValidator(validator, value) {
253-
if (value && !validator.regex.test(value)) {
254-
return false
255-
}
256-
return true
257-
}
258-
259-
// single validator
260-
const _validator = validationSchema[name].validator
261-
if (_validator && typeof _validator === 'object') {
262-
if (!_validateSingleValidator(_validator, value)) {
263-
return _validator.error
264-
}
265-
}
266-
267-
// multiple validators
268-
const _validators = validationSchema[name].validators
269-
if (_validators && typeof _validators === 'object' && Array.isArray(_validators)) {
270-
const errors = []
271-
_validators.forEach((_validator) => {
272-
if (!_validateSingleValidator(_validator, value)) {
273-
errors.push(_validator.error)
274-
}
275-
})
276-
if (errors.length > 0) {
277-
return errors
278-
}
279-
}
280-
281-
return ''
282-
}
283-
284-
const handleOnChange = useCallback(
285-
(event) => {
286-
setIsDirty(true)
287-
288-
const { name, value } = event.target
289-
const error = validateField(name, value)
290-
setState((prevState) => ({
291-
...prevState,
292-
[name]: { value, error },
293-
}))
294-
},
295-
[validationSchema],
296-
)
297-
298-
const handleOnSubmit = (event) => {
299-
event.preventDefault()
300-
const newState = Object.keys(validationSchema).reduce((agg, curr) => {
301-
agg[curr] = { ...state[curr], error: validateField(curr, state[curr].value) }
302-
return agg
303-
}, state)
304-
if (!validateState(newState)) {
305-
callback(state)
306-
} else {
307-
setState({ ...newState })
308-
}
309-
}
310-
return { state, disable, handleOnChange, handleOnSubmit }
311-
}
312-
313209
export function handleUTCTime(ts: string, isRelativeTime = false) {
314210
let timestamp = ''
315211
try {

src/Shared/Hooks/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@
1717
export * from './UsePrompt'
1818
export * from './useGetResourceKindsOptions'
1919
export * from './UseDownload'
20+
export * from './useForm'

src/Shared/Hooks/useForm/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './useForm'
2+
export * from './useForm.types'

0 commit comments

Comments
 (0)