mirror of
https://github.com/portainer/portainer.git
synced 2025-08-10 00:05:24 +02:00
fix(wizard): debounce name state [EE-4177] (#8042)
move debouncing to the component (from the validation). debounce returns undefined when it's not calling the debounced function, and undefined is considered a validation error.
This commit is contained in:
parent
253a3a2b40
commit
7006c17ce4
9 changed files with 74 additions and 58 deletions
|
@ -12,7 +12,7 @@ import {
|
|||
EdgeTypes,
|
||||
} from '@/react/portainer/environments/types';
|
||||
import { EnvironmentGroupId } from '@/react/portainer/environments/environment-groups/types';
|
||||
import { useDebounce } from '@/react/hooks/useDebounce';
|
||||
import { useDebouncedValue } from '@/react/hooks/useDebouncedValue';
|
||||
import {
|
||||
refetchIfAnyOffline,
|
||||
useEnvironmentList,
|
||||
|
@ -75,7 +75,7 @@ export function EnvironmentList({ onClickItem, onRefresh }: Props) {
|
|||
const [searchBarValue, setSearchBarValue] = useSearchBarState(storageKey);
|
||||
const [pageLimit, setPageLimit] = usePaginationLimitState(storageKey);
|
||||
const [page, setPage] = useState(1);
|
||||
const debouncedTextFilter = useDebounce(searchBarValue);
|
||||
const debouncedTextFilter = useDebouncedValue(searchBarValue);
|
||||
|
||||
const [connectionTypes, setConnectionTypes] = useHomePageFilter<
|
||||
Filter<ConnectionType>[]
|
||||
|
|
|
@ -1,30 +1,45 @@
|
|||
import { Field, useField } from 'formik';
|
||||
import { useField } from 'formik';
|
||||
import { string } from 'yup';
|
||||
import { useRef } from 'react';
|
||||
import _ from 'lodash';
|
||||
|
||||
import { getEnvironments } from '@/react/portainer/environments/environment.service';
|
||||
import { useDebounce } from '@/react/hooks/useDebounce';
|
||||
|
||||
import { FormControl } from '@@/form-components/FormControl';
|
||||
import { Input } from '@@/form-components/Input';
|
||||
|
||||
interface Props {
|
||||
readonly?: boolean;
|
||||
tooltip?: string;
|
||||
placeholder?: string;
|
||||
}
|
||||
|
||||
export function NameField({ readonly }: Props) {
|
||||
const [, meta] = useField('name');
|
||||
export function NameField({
|
||||
readonly,
|
||||
tooltip,
|
||||
placeholder = 'e.g. docker-prod01 / kubernetes-cluster01',
|
||||
}: Props) {
|
||||
const [{ value }, meta, { setValue }] = useField('name');
|
||||
|
||||
const id = 'name-input';
|
||||
|
||||
const [debouncedValue, setDebouncedValue] = useDebounce(value, setValue);
|
||||
|
||||
return (
|
||||
<FormControl label="Name" required errors={meta.error} inputId={id}>
|
||||
<Field
|
||||
<FormControl
|
||||
label="Name"
|
||||
required
|
||||
errors={meta.error}
|
||||
inputId={id}
|
||||
tooltip={tooltip}
|
||||
>
|
||||
<Input
|
||||
id={id}
|
||||
name="name"
|
||||
as={Input}
|
||||
onChange={(e) => setDebouncedValue(e.target.value)}
|
||||
value={debouncedValue}
|
||||
data-cy="endpointCreate-nameInput"
|
||||
placeholder="e.g. docker-prod01 / kubernetes-cluster01"
|
||||
placeholder={placeholder}
|
||||
readOnly={readonly}
|
||||
/>
|
||||
</FormControl>
|
||||
|
@ -37,26 +52,30 @@ export async function isNameUnique(name = '') {
|
|||
}
|
||||
|
||||
try {
|
||||
const result = await getEnvironments({ limit: 1, query: { name } });
|
||||
if (result.totalCount > 0) {
|
||||
return false;
|
||||
}
|
||||
const result = await getEnvironments({
|
||||
limit: 1,
|
||||
query: { name, excludeSnapshots: true },
|
||||
});
|
||||
return (
|
||||
result.totalCount === 0 || result.value.every((e) => e.Name !== name)
|
||||
);
|
||||
} catch (e) {
|
||||
// if backend fails to respond, assume name is unique, name validation happens also in the backend
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function cacheTest(
|
||||
asyncValidate: (val?: string) => Promise<boolean> | undefined
|
||||
) {
|
||||
let valid = false;
|
||||
let valid = true;
|
||||
let value = '';
|
||||
|
||||
return async (newValue = '') => {
|
||||
if (newValue !== value) {
|
||||
const response = await asyncValidate(newValue);
|
||||
value = newValue;
|
||||
|
||||
const response = await asyncValidate(newValue);
|
||||
valid = !!response;
|
||||
}
|
||||
return valid;
|
||||
|
@ -64,7 +83,7 @@ function cacheTest(
|
|||
}
|
||||
|
||||
export function useNameValidation() {
|
||||
const uniquenessTest = useRef(cacheTest(_.debounce(isNameUnique, 300)));
|
||||
const uniquenessTest = useRef(cacheTest(isNameUnique));
|
||||
|
||||
return string()
|
||||
.required('Name is required')
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue