1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-07-24 15:59:41 +02:00

refactor(ui): replace ng selectors with react-select [EE-3608] (#7203)

Co-authored-by: LP B <xAt0mZ@users.noreply.github.com>
This commit is contained in:
Chaim Lev-Ari 2022-09-21 10:10:58 +03:00 committed by GitHub
parent 1e21961e6a
commit ceaee4e175
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
66 changed files with 1188 additions and 625 deletions

View file

@ -0,0 +1,60 @@
import { components, MultiValueGenericProps } from 'react-select';
import { Select } from '@@/form-components/ReactSelect';
interface Option {
Name: string;
Description: string;
}
interface Props {
value: Option[];
onChange(storageClassName: string, value: readonly Option[]): void;
options: Option[];
inputId?: string;
storageClassName: string;
}
export function StorageAccessModeSelector({
value,
onChange,
options,
inputId,
storageClassName,
}: Props) {
return (
<Select
isMulti
getOptionLabel={(option) => option.Description}
getOptionValue={(option) => option.Name}
components={{ MultiValueLabel }}
options={options}
value={value}
closeMenuOnSelect={false}
onChange={(value) => onChange(storageClassName, value)}
inputId={inputId}
placeholder="Select one or more teams"
data-cy={`kubeSetup-storageAccessSelect${storageClassName}`}
/>
);
}
function MultiValueLabel({
data,
innerProps,
selectProps,
}: MultiValueGenericProps<Option>) {
if (!data || !data.Name) {
throw new Error('missing option name');
}
return (
<components.MultiValueLabel
data={data}
innerProps={innerProps}
selectProps={selectProps}
>
{data.Name}
</components.MultiValueLabel>
);
}

View file

@ -0,0 +1,50 @@
import _ from 'lodash';
import { Select } from '@@/form-components/ReactSelect';
interface Namespace {
id: string;
name: string;
}
interface Props {
name?: string;
value: string[];
onChange(value: string[]): void;
namespaces: Namespace[];
dataCy?: string;
inputId?: string;
placeholder?: string;
}
export function NamespacesSelector({
name,
value,
onChange,
namespaces,
dataCy,
inputId,
placeholder,
}: Props) {
return (
<Select
name={name}
isMulti
getOptionLabel={(namespace) => namespace.name}
getOptionValue={(namespace) => String(namespace.id)}
options={namespaces}
value={_.compact(
value.map((namespaceName) =>
namespaces.find((namespace) => namespace.name === namespaceName)
)
)}
closeMenuOnSelect={false}
onChange={(selectedTeams) =>
onChange(selectedTeams.map((namespace) => namespace.name))
}
data-cy={dataCy}
inputId={inputId}
placeholder={placeholder}
/>
);
}

View file

@ -0,0 +1,82 @@
import { User as UserIcon, Users as TeamIcon } from 'react-feather';
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 gap-1 items-center">
<Icon />
<span>{option.Name}</span>
<span>|</span>
<span>{option.Role.Name}</span>
</div>
);
}

View file

@ -0,0 +1,32 @@
import { Registry } from '@/portainer/environments/environment.service/registries';
import { Select } from '@@/form-components/ReactSelect';
interface Props {
value: Registry[];
onChange(value: readonly Registry[]): void;
options: Registry[];
inputId?: string;
}
export function CreateNamespaceRegistriesSelector({
value,
onChange,
options,
inputId,
}: Props) {
return (
<Select
isMulti
getOptionLabel={(option) => option.Name}
getOptionValue={(option) => String(option.Id)}
options={options}
value={value}
closeMenuOnSelect={false}
onChange={onChange}
inputId={inputId}
data-cy="namespaceCreate-registrySelect"
placeholder="Select one or more registry"
/>
);
}