diff --git a/app/portainer/components/forms/stack-redeploy-git-form/stack-redeploy-git-form.controller.js b/app/portainer/components/forms/stack-redeploy-git-form/stack-redeploy-git-form.controller.js index c53e96e76..262d278e8 100644 --- a/app/portainer/components/forms/stack-redeploy-git-form/stack-redeploy-git-form.controller.js +++ b/app/portainer/components/forms/stack-redeploy-git-form/stack-redeploy-git-form.controller.js @@ -182,7 +182,7 @@ class StackRedeployGitFormController { this.formValues.AutoUpdate = parseAutoUpdateResponse(this.stack.AutoUpdate); - if (this.stack.AutoUpdate.Webhook) { + if (this.stack.AutoUpdate && this.stack.AutoUpdate.Webhook) { this.state.webhookId = this.stack.AutoUpdate.Webhook; } diff --git a/app/react/hooks/useStateWrapper.ts b/app/react/hooks/useStateWrapper.ts new file mode 100644 index 000000000..f0bbc3d53 --- /dev/null +++ b/app/react/hooks/useStateWrapper.ts @@ -0,0 +1,19 @@ +import { useState, useCallback, useEffect } from 'react'; + +export function useStateWrapper(value: T, onChange: (value: T) => void) { + const [inputValue, setInputValue] = useState(value); + + const updateInputValue = useCallback( + (value: T) => { + setInputValue(value); + onChange(value); + }, + [onChange, setInputValue] + ); + + useEffect(() => { + setInputValue(value); + }, [value]); + + return [inputValue, updateInputValue] as const; +} diff --git a/app/react/portainer/gitops/AdditionalFilesField.tsx b/app/react/portainer/gitops/AdditionalFilesField.tsx index 47d506fbb..552d7adc4 100644 --- a/app/react/portainer/gitops/AdditionalFilesField.tsx +++ b/app/react/portainer/gitops/AdditionalFilesField.tsx @@ -1,9 +1,10 @@ import { FormikErrors } from 'formik'; +import { useStateWrapper } from '@/react/hooks/useStateWrapper'; + import { FormError } from '@@/form-components/FormError'; import { InputGroup } from '@@/form-components/InputGroup'; import { InputList, ItemProps } from '@@/form-components/InputList'; -import { useCaretPosition } from '@@/form-components/useCaretPosition'; interface Props { value: Array; @@ -32,21 +33,19 @@ function Item({ error, readOnly, }: ItemProps) { - const { ref, updateCaret } = useCaretPosition(); + const [inputValue, updateInputValue] = useStateWrapper(item, onChange); return (
path { - onChange(e.target.value); - updateCaret(); + updateInputValue(e.target.value); }} /> diff --git a/app/react/portainer/gitops/ComposePathField/ComposePathField.tsx b/app/react/portainer/gitops/ComposePathField/ComposePathField.tsx index f8a4b3e19..c8b1bd06b 100644 --- a/app/react/portainer/gitops/ComposePathField/ComposePathField.tsx +++ b/app/react/portainer/gitops/ComposePathField/ComposePathField.tsx @@ -1,7 +1,8 @@ +import { useStateWrapper } from '@/react/hooks/useStateWrapper'; + import { FormControl } from '@@/form-components/FormControl'; import { TextTip } from '@@/Tip/TextTip'; import { Input } from '@@/form-components/Input'; -import { useCaretPosition } from '@@/form-components/useCaretPosition'; import { GitFormModel } from '../types'; import { isBE } from '../../feature-flags/feature-flags.service'; @@ -25,7 +26,7 @@ export function ComposePathField({ isDockerStandalone, errors, }: Props) { - const { ref, updateCaret } = useCaretPosition(); + const [inputValue, updateInputValue] = useStateWrapper(value, onChange); return (
@@ -65,11 +66,9 @@ export function ComposePathField({ /> ) : ( { - onChange(e.target.value); - updateCaret(); + updateInputValue(e.target.value); }} placeholder={isCompose ? 'docker-compose.yml' : 'manifest.yml'} /> diff --git a/app/react/portainer/gitops/ComposePathField/PathSelector.tsx b/app/react/portainer/gitops/ComposePathField/PathSelector.tsx index 935edcd87..9f4e41144 100644 --- a/app/react/portainer/gitops/ComposePathField/PathSelector.tsx +++ b/app/react/portainer/gitops/ComposePathField/PathSelector.tsx @@ -12,8 +12,6 @@ import clsx from 'clsx'; import { useSearch } from '@/react/portainer/gitops/queries/useSearch'; import { useDebounce } from '@/react/hooks/useDebounce'; -import { useCaretPosition } from '@@/form-components/useCaretPosition'; - import { getAuthentication } from '../utils'; import { GitFormModel } from '../types'; @@ -30,7 +28,7 @@ export function PathSelector({ placeholder: string; model: GitFormModel; }) { - const [searchTerm, setSearchTerm] = useDebounce('', () => {}); + const [searchTerm, setSearchTerm] = useDebounce(value, onChange); const creds = getAuthentication(model); const payload = { @@ -43,7 +41,6 @@ export function PathSelector({ model.RepositoryURL && model.RepositoryURLValid && searchTerm ); const { data: searchResults } = useSearch(payload, enabled); - const { ref, updateCaret } = useCaretPosition(); return ( {searchResults && searchResults.length > 0 && ( @@ -81,12 +77,9 @@ export function PathSelector({ function handleChange(e: ChangeEvent) { setSearchTerm(e.target.value); - onChange(e.target.value); - updateCaret(); } function onSelect(value: string) { - setSearchTerm(''); onChange(value); } } diff --git a/app/react/portainer/gitops/RefField/RefField.tsx b/app/react/portainer/gitops/RefField/RefField.tsx index 896099002..fb65af145 100644 --- a/app/react/portainer/gitops/RefField/RefField.tsx +++ b/app/react/portainer/gitops/RefField/RefField.tsx @@ -2,6 +2,7 @@ import { PropsWithChildren, ReactNode } from 'react'; import { SchemaOf, string } from 'yup'; import { StackId } from '@/react/docker/stacks/types'; +import { useStateWrapper } from '@/react/hooks/useStateWrapper'; import { FormControl } from '@@/form-components/FormControl'; import { Input } from '@@/form-components/Input'; @@ -29,6 +30,8 @@ export function RefField({ isUrlValid, stackId, }: Props) { + const [inputValue, updateInputValue] = useStateWrapper(value, onChange); + return isBE ? ( onChange(e.target.value)} + value={inputValue} + onChange={(e) => updateInputValue(e.target.value)} placeholder="refs/heads/main" />