You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

132 lines
3.7 KiB
TypeScript

// Copyright (C) 2020-2021 Intel Corporation
//
// SPDX-License-Identifier: MIT
import React, { useState, useEffect, useRef } from 'react';
import { SelectValue, RefSelectProps } from 'antd/lib/select';
import Autocomplete from 'antd/lib/auto-complete';
import Input from 'antd/lib/input';
import debounce from 'lodash/debounce';
import getCore from 'cvat-core-wrapper';
const core = getCore();
export interface User {
id: number;
username: string;
}
interface Props {
value: User | null;
className?: string;
onSelect: (user: User | null) => void;
}
const searchUsers = debounce(
(searchValue: string, setUsers: (users: User[]) => void): void => {
core.users
.get({
search: searchValue,
limit: 10,
is_active: true,
})
.then((result: User[]) => {
if (result) {
setUsers(result);
}
});
},
250,
{
maxWait: 750,
},
);
export default function UserSelector(props: Props): JSX.Element {
const { value, className, onSelect } = props;
const [searchPhrase, setSearchPhrase] = useState('');
const [initialUsers, setInitialUsers] = useState<User[]>([]);
const [users, setUsers] = useState<User[]>([]);
const autocompleteRef = useRef<RefSelectProps | null>(null);
useEffect(() => {
core.users.get({ limit: 10, is_active: true }).then((result: User[]) => {
if (result) {
setInitialUsers(result);
}
});
}, []);
useEffect(() => {
setUsers(initialUsers);
}, [initialUsers]);
useEffect(() => {
if (searchPhrase) {
searchUsers(searchPhrase, setUsers);
} else {
setUsers(initialUsers);
}
}, [searchPhrase]);
const handleSearch = (searchValue: string): void => {
setSearchPhrase(searchValue);
};
const onBlur = (): void => {
if (!searchPhrase && value) {
onSelect(null);
} else if (searchPhrase) {
const potentialUsers = users.filter((_user) => _user.username.includes(searchPhrase));
if (potentialUsers.length === 1) {
setSearchPhrase(potentialUsers[0].username);
onSelect(potentialUsers[0]);
} else {
setSearchPhrase(value?.username || '');
}
}
};
const handleSelect = (_value: SelectValue): void => {
const user = _value ? users.filter((_user) => _user.id === +_value)[0] : null;
if ((user?.id || null) !== (value?.id || null)) {
onSelect(user);
}
};
useEffect(() => {
if (value) {
if (!users.filter((user) => user.id === value.id).length) {
core.users.get({ id: value.id }).then((result: User[]) => {
const [user] = result;
if (user) {
setUsers([...users, user]);
}
});
}
setSearchPhrase(value.username);
}
}, [value]);
const combinedClassName = className ? `${className} cvat-user-search-field` : 'cvat-user-search-field';
return (
<Autocomplete
ref={autocompleteRef}
value={searchPhrase}
placeholder='Select a user'
onSearch={handleSearch}
onSelect={handleSelect}
onBlur={onBlur}
className={combinedClassName}
options={users.map((user) => ({
value: user.id.toString(),
label: user.username,
}))}
>
<Input onPressEnter={() => autocompleteRef.current?.blur()} />
</Autocomplete>
);
}