mirror of
https://github.com/prometheus/prometheus.git
synced 2025-03-05 20:59:13 -08:00
141 lines
3.5 KiB
TypeScript
141 lines
3.5 KiB
TypeScript
|
import { FC, useState } from "react";
|
||
|
import {
|
||
|
Badge,
|
||
|
CheckIcon,
|
||
|
CloseButton,
|
||
|
Combobox,
|
||
|
ComboboxChevron,
|
||
|
ComboboxClearButton,
|
||
|
Group,
|
||
|
Input,
|
||
|
MantineColor,
|
||
|
Pill,
|
||
|
PillGroup,
|
||
|
PillsInput,
|
||
|
useCombobox,
|
||
|
} from "@mantine/core";
|
||
|
import { IconActivity, IconFilter } from "@tabler/icons-react";
|
||
|
|
||
|
interface StatePillProps extends React.ComponentPropsWithoutRef<"div"> {
|
||
|
value: string;
|
||
|
onRemove?: () => void;
|
||
|
}
|
||
|
|
||
|
export function StatePill({ value, onRemove, ...others }: StatePillProps) {
|
||
|
return (
|
||
|
<Pill
|
||
|
fw={600}
|
||
|
style={{ textTransform: "uppercase", fontWeight: 600 }}
|
||
|
onRemove={onRemove}
|
||
|
{...others}
|
||
|
withRemoveButton={!!onRemove}
|
||
|
>
|
||
|
{value}
|
||
|
</Pill>
|
||
|
);
|
||
|
}
|
||
|
|
||
|
interface StateMultiSelectProps {
|
||
|
options: string[];
|
||
|
optionClass: (option: string) => string;
|
||
|
placeholder: string;
|
||
|
values: string[];
|
||
|
onChange: (values: string[]) => void;
|
||
|
}
|
||
|
|
||
|
export const StateMultiSelect: FC<StateMultiSelectProps> = ({
|
||
|
options,
|
||
|
optionClass,
|
||
|
placeholder,
|
||
|
values,
|
||
|
onChange,
|
||
|
}) => {
|
||
|
const combobox = useCombobox({
|
||
|
onDropdownClose: () => combobox.resetSelectedOption(),
|
||
|
onDropdownOpen: () => combobox.updateSelectedOptionIndex("active"),
|
||
|
});
|
||
|
|
||
|
const handleValueSelect = (val: string) =>
|
||
|
onChange(
|
||
|
values.includes(val) ? values.filter((v) => v !== val) : [...values, val]
|
||
|
);
|
||
|
|
||
|
const handleValueRemove = (val: string) =>
|
||
|
onChange(values.filter((v) => v !== val));
|
||
|
|
||
|
const renderedValues = values.map((item) => (
|
||
|
<StatePill
|
||
|
value={item}
|
||
|
className={optionClass(item)}
|
||
|
onRemove={() => handleValueRemove(item)}
|
||
|
key={item}
|
||
|
/>
|
||
|
));
|
||
|
|
||
|
return (
|
||
|
<Combobox
|
||
|
store={combobox}
|
||
|
onOptionSubmit={handleValueSelect}
|
||
|
withinPortal={false}
|
||
|
>
|
||
|
<Combobox.DropdownTarget>
|
||
|
<PillsInput
|
||
|
pointer
|
||
|
onClick={() => combobox.toggleDropdown()}
|
||
|
miw={200}
|
||
|
leftSection={<IconActivity size={14} />}
|
||
|
rightSection={
|
||
|
values.length > 0 ? (
|
||
|
<ComboboxClearButton onClear={() => onChange([])} />
|
||
|
) : (
|
||
|
<ComboboxChevron />
|
||
|
)
|
||
|
}
|
||
|
>
|
||
|
<Pill.Group>
|
||
|
{renderedValues.length > 0 ? (
|
||
|
renderedValues
|
||
|
) : (
|
||
|
<PillsInput.Field placeholder={placeholder} mt={1} />
|
||
|
)}
|
||
|
|
||
|
<Combobox.EventsTarget>
|
||
|
<PillsInput.Field
|
||
|
type="hidden"
|
||
|
onBlur={() => combobox.closeDropdown()}
|
||
|
onKeyDown={(event) => {
|
||
|
if (event.key === "Backspace") {
|
||
|
event.preventDefault();
|
||
|
handleValueRemove(values[values.length - 1]);
|
||
|
}
|
||
|
}}
|
||
|
/>
|
||
|
</Combobox.EventsTarget>
|
||
|
</Pill.Group>
|
||
|
</PillsInput>
|
||
|
</Combobox.DropdownTarget>
|
||
|
|
||
|
<Combobox.Dropdown>
|
||
|
<Combobox.Options>
|
||
|
{options.map((value) => {
|
||
|
return (
|
||
|
<Combobox.Option
|
||
|
value={value}
|
||
|
key={value}
|
||
|
active={values.includes(value)}
|
||
|
>
|
||
|
<Group gap="sm">
|
||
|
{values.includes(value) ? (
|
||
|
<CheckIcon size={12} color="gray" />
|
||
|
) : null}
|
||
|
<StatePill value={value} className={optionClass(value)} />
|
||
|
</Group>
|
||
|
</Combobox.Option>
|
||
|
);
|
||
|
})}
|
||
|
</Combobox.Options>
|
||
|
</Combobox.Dropdown>
|
||
|
</Combobox>
|
||
|
);
|
||
|
};
|