123 lines
4.3 KiB
TypeScript
123 lines
4.3 KiB
TypeScript
import { Combobox, TextInput, useCombobox } from "@mantine/core";
|
|
import { useEffect, useState } from "react";
|
|
import { ipInterfacesQuery } from "../js/utils";
|
|
|
|
interface ItemProps{
|
|
value: string
|
|
netint: string;
|
|
}
|
|
|
|
interface InterfaceInputProps{
|
|
initialCustomInterfaces?:ItemProps[],
|
|
includeInterfaceNames?:boolean,
|
|
onChange?: (value:string) => void,
|
|
value?:string,
|
|
defaultValue?:string
|
|
}
|
|
|
|
export const InterfaceInput = ({ initialCustomInterfaces, includeInterfaceNames, onChange, value, defaultValue }:InterfaceInputProps) => {
|
|
|
|
const [customIpInterfaces, setCustomIpInterfaces] = useState<ItemProps[]>(initialCustomInterfaces??[]);
|
|
const interfacesQuery = ipInterfacesQuery()
|
|
|
|
const getInterfaces = () => {
|
|
if (interfacesQuery.isLoading || !interfacesQuery.data) return []
|
|
if(includeInterfaceNames){
|
|
const result = interfacesQuery.data.map(item => ({netint:"IP", value:item.addr})) as ItemProps[]
|
|
interfacesQuery.data.map(item => item.name).filter((item, index, arr) => arr.indexOf(item) === index).forEach(item => result.push({netint:"INT", value:item}))
|
|
return result
|
|
}
|
|
return (interfacesQuery.data.map(item => ({netint:item.name, value:item.addr})) as ItemProps[])
|
|
}
|
|
|
|
const interfaces = getInterfaces()
|
|
|
|
const combobox = useCombobox({
|
|
onDropdownClose: () => {
|
|
combobox.resetSelectedOption()
|
|
},
|
|
});
|
|
|
|
const data = [...customIpInterfaces.filter(v => !interfaces.map(v => v.value).includes(v.value)), ...interfaces]
|
|
const [selectedValue, setSelectedValue] = useState<string | null>(null);
|
|
const [search, setSearch] = useState('');
|
|
|
|
const exactOptionMatch: ItemProps|undefined = data.find((item) => item.value === search);
|
|
|
|
const filteredOptions = data.filter((item) => item.value.toLowerCase().includes(search.toLowerCase().trim())).sort((a, b) => {
|
|
if (exactOptionMatch != null) {
|
|
if (a.value == exactOptionMatch.value) return -1
|
|
if (b.value == exactOptionMatch.value) return 1
|
|
}
|
|
return a.value.localeCompare(b.value)
|
|
});
|
|
|
|
const options = filteredOptions.sort( (a, b) => a.value == selectedValue? -1 : b.value == selectedValue? 1: a.value.localeCompare(b.value) ).map((item) => (
|
|
<Combobox.Option value={item.value} key={item.value}>
|
|
( <b>{item.value == selectedValue ? "SELECTED" : item.netint}</b> ) -{">"} <b>{item.value}</b>
|
|
</Combobox.Option>
|
|
));
|
|
|
|
useEffect(() => {
|
|
setSelectedValue(data.find((item) => item.value === defaultValue)?.value??null)
|
|
setSearch(defaultValue??'')
|
|
}, [])
|
|
|
|
return <>
|
|
<Combobox
|
|
store={combobox}
|
|
withinPortal={false}
|
|
position="bottom-end"
|
|
onOptionSubmit={(value) => {
|
|
if (value === '$create') {
|
|
const item = { value: search, netint: "CUSTOM" };
|
|
setCustomIpInterfaces((current) => [...current, item]);
|
|
setSelectedValue(search);
|
|
onChange?.(search)
|
|
} else {
|
|
setSelectedValue(value);
|
|
setSearch(value);
|
|
onChange?.(value)
|
|
}
|
|
combobox.closeDropdown();
|
|
}}
|
|
>
|
|
|
|
<Combobox.Target>
|
|
<TextInput
|
|
style={{width:"100%"}}
|
|
rightSection={<Combobox.Chevron />}
|
|
value={value??search}
|
|
placeholder="10.1.1.1"
|
|
rightSectionPointerEvents="none"
|
|
onChange={(event) => {
|
|
combobox.openDropdown();
|
|
combobox.updateSelectedOptionIndex();
|
|
setSearch(event.currentTarget.value)
|
|
onChange?.(event.currentTarget.value)
|
|
|
|
}}
|
|
onClick={(e) => {
|
|
combobox.openDropdown()
|
|
}}
|
|
onFocus={(e) => {
|
|
combobox.openDropdown()
|
|
}}
|
|
onBlur={(e) => {
|
|
combobox.closeDropdown();
|
|
setSearch(selectedValue??'');
|
|
}}
|
|
/>
|
|
</Combobox.Target>
|
|
|
|
<Combobox.Dropdown>
|
|
<Combobox.Options mah={200} style={{ overflowY: 'auto' }}>
|
|
{options}
|
|
{(exactOptionMatch==null) && search.trim().length > 0 && (
|
|
<Combobox.Option value="$create">+ Use this: {search}</Combobox.Option>
|
|
)}
|
|
</Combobox.Options>
|
|
</Combobox.Dropdown>
|
|
</Combobox>
|
|
</>
|
|
} |