mirror of https://github.com/portainer/portainer
fix(stack/git): fix cursor movement issue in git text fields (#8656)
parent
3a30c8ed1e
commit
0ca56ddbb1
|
@ -182,7 +182,7 @@ class StackRedeployGitFormController {
|
||||||
|
|
||||||
this.formValues.AutoUpdate = parseAutoUpdateResponse(this.stack.AutoUpdate);
|
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;
|
this.state.webhookId = this.stack.AutoUpdate.Webhook;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { useState, useCallback, useEffect } from 'react';
|
||||||
|
|
||||||
|
export function useStateWrapper<T>(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;
|
||||||
|
}
|
|
@ -1,9 +1,10 @@
|
||||||
import { FormikErrors } from 'formik';
|
import { FormikErrors } from 'formik';
|
||||||
|
|
||||||
|
import { useStateWrapper } from '@/react/hooks/useStateWrapper';
|
||||||
|
|
||||||
import { FormError } from '@@/form-components/FormError';
|
import { FormError } from '@@/form-components/FormError';
|
||||||
import { InputGroup } from '@@/form-components/InputGroup';
|
import { InputGroup } from '@@/form-components/InputGroup';
|
||||||
import { InputList, ItemProps } from '@@/form-components/InputList';
|
import { InputList, ItemProps } from '@@/form-components/InputList';
|
||||||
import { useCaretPosition } from '@@/form-components/useCaretPosition';
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
value: Array<string>;
|
value: Array<string>;
|
||||||
|
@ -32,21 +33,19 @@ function Item({
|
||||||
error,
|
error,
|
||||||
readOnly,
|
readOnly,
|
||||||
}: ItemProps<string>) {
|
}: ItemProps<string>) {
|
||||||
const { ref, updateCaret } = useCaretPosition();
|
const [inputValue, updateInputValue] = useStateWrapper(item, onChange);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative flex flex-col">
|
<div className="relative flex flex-col">
|
||||||
<InputGroup size="small">
|
<InputGroup size="small">
|
||||||
<InputGroup.Addon>path</InputGroup.Addon>
|
<InputGroup.Addon>path</InputGroup.Addon>
|
||||||
<InputGroup.Input
|
<InputGroup.Input
|
||||||
mRef={ref}
|
|
||||||
required
|
required
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
readOnly={readOnly}
|
readOnly={readOnly}
|
||||||
value={item}
|
value={inputValue}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
onChange(e.target.value);
|
updateInputValue(e.target.value);
|
||||||
updateCaret();
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</InputGroup>
|
</InputGroup>
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
|
import { useStateWrapper } from '@/react/hooks/useStateWrapper';
|
||||||
|
|
||||||
import { FormControl } from '@@/form-components/FormControl';
|
import { FormControl } from '@@/form-components/FormControl';
|
||||||
import { TextTip } from '@@/Tip/TextTip';
|
import { TextTip } from '@@/Tip/TextTip';
|
||||||
import { Input } from '@@/form-components/Input';
|
import { Input } from '@@/form-components/Input';
|
||||||
import { useCaretPosition } from '@@/form-components/useCaretPosition';
|
|
||||||
|
|
||||||
import { GitFormModel } from '../types';
|
import { GitFormModel } from '../types';
|
||||||
import { isBE } from '../../feature-flags/feature-flags.service';
|
import { isBE } from '../../feature-flags/feature-flags.service';
|
||||||
|
@ -25,7 +26,7 @@ export function ComposePathField({
|
||||||
isDockerStandalone,
|
isDockerStandalone,
|
||||||
errors,
|
errors,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const { ref, updateCaret } = useCaretPosition();
|
const [inputValue, updateInputValue] = useStateWrapper(value, onChange);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
|
@ -65,11 +66,9 @@ export function ComposePathField({
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Input
|
<Input
|
||||||
mRef={ref}
|
value={inputValue}
|
||||||
value={value}
|
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
onChange(e.target.value);
|
updateInputValue(e.target.value);
|
||||||
updateCaret();
|
|
||||||
}}
|
}}
|
||||||
placeholder={isCompose ? 'docker-compose.yml' : 'manifest.yml'}
|
placeholder={isCompose ? 'docker-compose.yml' : 'manifest.yml'}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -12,8 +12,6 @@ import clsx from 'clsx';
|
||||||
import { useSearch } from '@/react/portainer/gitops/queries/useSearch';
|
import { useSearch } from '@/react/portainer/gitops/queries/useSearch';
|
||||||
import { useDebounce } from '@/react/hooks/useDebounce';
|
import { useDebounce } from '@/react/hooks/useDebounce';
|
||||||
|
|
||||||
import { useCaretPosition } from '@@/form-components/useCaretPosition';
|
|
||||||
|
|
||||||
import { getAuthentication } from '../utils';
|
import { getAuthentication } from '../utils';
|
||||||
import { GitFormModel } from '../types';
|
import { GitFormModel } from '../types';
|
||||||
|
|
||||||
|
@ -30,7 +28,7 @@ export function PathSelector({
|
||||||
placeholder: string;
|
placeholder: string;
|
||||||
model: GitFormModel;
|
model: GitFormModel;
|
||||||
}) {
|
}) {
|
||||||
const [searchTerm, setSearchTerm] = useDebounce('', () => {});
|
const [searchTerm, setSearchTerm] = useDebounce(value, onChange);
|
||||||
|
|
||||||
const creds = getAuthentication(model);
|
const creds = getAuthentication(model);
|
||||||
const payload = {
|
const payload = {
|
||||||
|
@ -43,7 +41,6 @@ export function PathSelector({
|
||||||
model.RepositoryURL && model.RepositoryURLValid && searchTerm
|
model.RepositoryURL && model.RepositoryURLValid && searchTerm
|
||||||
);
|
);
|
||||||
const { data: searchResults } = useSearch(payload, enabled);
|
const { data: searchResults } = useSearch(payload, enabled);
|
||||||
const { ref, updateCaret } = useCaretPosition();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Combobox
|
<Combobox
|
||||||
|
@ -53,11 +50,10 @@ export function PathSelector({
|
||||||
data-cy="component-gitComposeInput"
|
data-cy="component-gitComposeInput"
|
||||||
>
|
>
|
||||||
<ComboboxInput
|
<ComboboxInput
|
||||||
ref={ref}
|
|
||||||
className="form-control"
|
className="form-control"
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
value={value}
|
value={searchTerm}
|
||||||
/>
|
/>
|
||||||
{searchResults && searchResults.length > 0 && (
|
{searchResults && searchResults.length > 0 && (
|
||||||
<ComboboxPopover>
|
<ComboboxPopover>
|
||||||
|
@ -81,12 +77,9 @@ export function PathSelector({
|
||||||
|
|
||||||
function handleChange(e: ChangeEvent<HTMLInputElement>) {
|
function handleChange(e: ChangeEvent<HTMLInputElement>) {
|
||||||
setSearchTerm(e.target.value);
|
setSearchTerm(e.target.value);
|
||||||
onChange(e.target.value);
|
|
||||||
updateCaret();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function onSelect(value: string) {
|
function onSelect(value: string) {
|
||||||
setSearchTerm('');
|
|
||||||
onChange(value);
|
onChange(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { PropsWithChildren, ReactNode } from 'react';
|
||||||
import { SchemaOf, string } from 'yup';
|
import { SchemaOf, string } from 'yup';
|
||||||
|
|
||||||
import { StackId } from '@/react/docker/stacks/types';
|
import { StackId } from '@/react/docker/stacks/types';
|
||||||
|
import { useStateWrapper } from '@/react/hooks/useStateWrapper';
|
||||||
|
|
||||||
import { FormControl } from '@@/form-components/FormControl';
|
import { FormControl } from '@@/form-components/FormControl';
|
||||||
import { Input } from '@@/form-components/Input';
|
import { Input } from '@@/form-components/Input';
|
||||||
|
@ -29,6 +30,8 @@ export function RefField({
|
||||||
isUrlValid,
|
isUrlValid,
|
||||||
stackId,
|
stackId,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
|
const [inputValue, updateInputValue] = useStateWrapper(value, onChange);
|
||||||
|
|
||||||
return isBE ? (
|
return isBE ? (
|
||||||
<Wrapper
|
<Wrapper
|
||||||
errors={error}
|
errors={error}
|
||||||
|
@ -62,8 +65,8 @@ export function RefField({
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Input
|
<Input
|
||||||
value={value}
|
value={inputValue}
|
||||||
onChange={(e) => onChange(e.target.value)}
|
onChange={(e) => updateInputValue(e.target.value)}
|
||||||
placeholder="refs/heads/main"
|
placeholder="refs/heads/main"
|
||||||
/>
|
/>
|
||||||
</Wrapper>
|
</Wrapper>
|
||||||
|
|
Loading…
Reference in New Issue