mirror of
https://github.com/portainer/portainer.git
synced 2025-07-20 13:59:40 +02:00
Some checks are pending
ci / build_images (map[arch:amd64 platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:amd64 platform:windows version:1809]) (push) Waiting to run
ci / build_images (map[arch:amd64 platform:windows version:ltsc2022]) (push) Waiting to run
ci / build_images (map[arch:arm platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:arm64 platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:ppc64le platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:s390x platform:linux version:]) (push) Waiting to run
ci / build_manifests (push) Blocked by required conditions
/ triage (push) Waiting to run
Lint / Run linters (push) Waiting to run
Test / test-client (push) Waiting to run
Test / test-server (map[arch:amd64 platform:linux]) (push) Waiting to run
Test / test-server (map[arch:amd64 platform:windows version:1809]) (push) Waiting to run
Test / test-server (map[arch:amd64 platform:windows version:ltsc2022]) (push) Waiting to run
Test / test-server (map[arch:arm64 platform:linux]) (push) Waiting to run
82 lines
2 KiB
TypeScript
82 lines
2 KiB
TypeScript
import { User as UserIcon, Users as TeamIcon } from 'lucide-react';
|
|
import { OptionProps, components, MultiValueGenericProps } from 'react-select';
|
|
|
|
import { Select } from '@@/form-components/ReactSelect';
|
|
|
|
type Role = { Name: string };
|
|
type Option = { Type: 'user' | 'team'; Id: number; Name: string; Role: Role };
|
|
|
|
interface Props {
|
|
name?: string;
|
|
value: Option[];
|
|
onChange(value: readonly Option[]): void;
|
|
options: Option[];
|
|
dataCy: string;
|
|
inputId?: string;
|
|
placeholder?: string;
|
|
}
|
|
|
|
export function NamespaceAccessUsersSelector({
|
|
onChange,
|
|
options,
|
|
value,
|
|
dataCy,
|
|
inputId,
|
|
name,
|
|
placeholder,
|
|
}: Props) {
|
|
return (
|
|
<Select
|
|
isMulti
|
|
name={name}
|
|
getOptionLabel={(option) => option.Name}
|
|
getOptionValue={(option) => `${option.Id}-${option.Type}`}
|
|
options={options}
|
|
value={value}
|
|
closeMenuOnSelect={false}
|
|
onChange={onChange}
|
|
data-cy={dataCy}
|
|
inputId={inputId}
|
|
placeholder={placeholder}
|
|
components={{ MultiValueLabel, Option: OptionComponent }}
|
|
/>
|
|
);
|
|
}
|
|
|
|
function isOption(option: unknown): option is Option {
|
|
return !!option && typeof option === 'object' && 'Type' in option;
|
|
}
|
|
|
|
function OptionComponent({ data, ...props }: OptionProps<Option, true>) {
|
|
return (
|
|
// eslint-disable-next-line react/jsx-props-no-spreading
|
|
<components.Option data={data} {...props}>
|
|
{isOption(data) && <Label option={data} />}
|
|
</components.Option>
|
|
);
|
|
}
|
|
|
|
function MultiValueLabel({
|
|
data,
|
|
...props
|
|
}: MultiValueGenericProps<Option, true>) {
|
|
return (
|
|
// eslint-disable-next-line react/jsx-props-no-spreading
|
|
<components.MultiValueLabel data={data} {...props}>
|
|
{isOption(data) && <Label option={data} />}
|
|
</components.MultiValueLabel>
|
|
);
|
|
}
|
|
|
|
function Label({ option }: { option: Option }) {
|
|
const Icon = option.Type === 'user' ? UserIcon : TeamIcon;
|
|
|
|
return (
|
|
<div className="flex items-center gap-1">
|
|
<Icon />
|
|
<span>{option.Name}</span>
|
|
<span>|</span>
|
|
<span>{option.Role.Name}</span>
|
|
</div>
|
|
);
|
|
}
|