converted client select to ui-shared (#27799)
Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>
This commit is contained in:
parent
42244d2a67
commit
63bd46b8cd
2 changed files with 45 additions and 66 deletions
|
@ -1,15 +1,9 @@
|
||||||
import type ClientRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientRepresentation";
|
import type ClientRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientRepresentation";
|
||||||
import type { ClientQuery } from "@keycloak/keycloak-admin-client/lib/resources/clients";
|
import type { ClientQuery } from "@keycloak/keycloak-admin-client/lib/resources/clients";
|
||||||
import {
|
import { SelectVariant } from "@patternfly/react-core";
|
||||||
FormGroup,
|
|
||||||
Select,
|
|
||||||
SelectOption,
|
|
||||||
SelectVariant,
|
|
||||||
} from "@patternfly/react-core";
|
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { Controller, useFormContext } from "react-hook-form";
|
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { HelpItem } from "ui-shared";
|
import { SelectControl } from "ui-shared";
|
||||||
|
|
||||||
import { adminClient } from "../../admin-client";
|
import { adminClient } from "../../admin-client";
|
||||||
import { useFetch } from "../../utils/useFetch";
|
import { useFetch } from "../../utils/useFetch";
|
||||||
|
@ -26,12 +20,7 @@ export const ClientSelect = ({
|
||||||
required = false,
|
required = false,
|
||||||
}: ClientSelectProps) => {
|
}: ClientSelectProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const {
|
|
||||||
control,
|
|
||||||
formState: { errors },
|
|
||||||
} = useFormContext();
|
|
||||||
|
|
||||||
const [open, setOpen] = useState(false);
|
|
||||||
const [clients, setClients] = useState<ClientRepresentation[]>([]);
|
const [clients, setClients] = useState<ClientRepresentation[]>([]);
|
||||||
const [search, setSearch] = useState("");
|
const [search, setSearch] = useState("");
|
||||||
|
|
||||||
|
@ -50,51 +39,27 @@ export const ClientSelect = ({
|
||||||
[search],
|
[search],
|
||||||
);
|
);
|
||||||
|
|
||||||
const convert = (clients: ClientRepresentation[]) => [
|
|
||||||
<SelectOption key="empty" value="">
|
|
||||||
{t("none")}
|
|
||||||
</SelectOption>,
|
|
||||||
...clients.map((option) => (
|
|
||||||
<SelectOption key={option.id} value={option.clientId} />
|
|
||||||
)),
|
|
||||||
];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormGroup
|
<SelectControl
|
||||||
|
name={name!}
|
||||||
label={t(label!)}
|
label={t(label!)}
|
||||||
isRequired={required}
|
labelIcon={t(helpText!)}
|
||||||
labelIcon={<HelpItem helpText={t(helpText!)} fieldLabelId={label!} />}
|
controller={{
|
||||||
fieldId={name!}
|
defaultValue: defaultValue || "",
|
||||||
validated={errors[name!] ? "error" : "default"}
|
rules: {
|
||||||
helperTextInvalid={t("required")}
|
required: {
|
||||||
>
|
value: required,
|
||||||
<Controller
|
message: t("required"),
|
||||||
name={name!}
|
},
|
||||||
defaultValue={defaultValue || ""}
|
},
|
||||||
control={control}
|
}}
|
||||||
rules={required ? { required: true } : {}}
|
onFilter={(value) => setSearch(value)}
|
||||||
render={({ field }) => (
|
variant={SelectVariant.typeahead}
|
||||||
<Select
|
isDisabled={isDisabled}
|
||||||
toggleId={name}
|
options={[
|
||||||
variant={SelectVariant.typeahead}
|
{ key: "", value: t("none") },
|
||||||
onToggle={(open) => setOpen(open)}
|
...clients.map(({ id, clientId }) => ({ key: id!, value: clientId! })),
|
||||||
isOpen={open}
|
]}
|
||||||
isDisabled={isDisabled}
|
/>
|
||||||
selections={field.value}
|
|
||||||
onFilter={(_, value) => {
|
|
||||||
setSearch(value);
|
|
||||||
return convert(clients);
|
|
||||||
}}
|
|
||||||
onSelect={(_, value) => {
|
|
||||||
field.onChange(value.toString());
|
|
||||||
setOpen(false);
|
|
||||||
}}
|
|
||||||
typeAheadAriaLabel={t(label!)}
|
|
||||||
>
|
|
||||||
{convert(clients)}
|
|
||||||
</Select>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -26,7 +26,13 @@ export type SelectControlProps<
|
||||||
P extends FieldPath<T> = FieldPath<T>,
|
P extends FieldPath<T> = FieldPath<T>,
|
||||||
> = Omit<
|
> = Omit<
|
||||||
SelectProps,
|
SelectProps,
|
||||||
"name" | "onToggle" | "selections" | "onSelect" | "onClear" | "isOpen"
|
| "name"
|
||||||
|
| "onToggle"
|
||||||
|
| "selections"
|
||||||
|
| "onSelect"
|
||||||
|
| "onClear"
|
||||||
|
| "isOpen"
|
||||||
|
| "onFilter"
|
||||||
> &
|
> &
|
||||||
UseControllerProps<T, P> & {
|
UseControllerProps<T, P> & {
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -34,6 +40,7 @@ export type SelectControlProps<
|
||||||
options: string[] | SelectControlOption[];
|
options: string[] | SelectControlOption[];
|
||||||
labelIcon?: string;
|
labelIcon?: string;
|
||||||
controller: Omit<ControllerProps, "name" | "render">;
|
controller: Omit<ControllerProps, "name" | "render">;
|
||||||
|
onFilter?: (value: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SelectControl = <
|
export const SelectControl = <
|
||||||
|
@ -46,6 +53,7 @@ export const SelectControl = <
|
||||||
controller,
|
controller,
|
||||||
variant = SelectVariant.single,
|
variant = SelectVariant.single,
|
||||||
labelIcon,
|
labelIcon,
|
||||||
|
onFilter,
|
||||||
...rest
|
...rest
|
||||||
}: SelectControlProps<T, P>) => {
|
}: SelectControlProps<T, P>) => {
|
||||||
const {
|
const {
|
||||||
|
@ -53,6 +61,15 @@ export const SelectControl = <
|
||||||
formState: { errors },
|
formState: { errors },
|
||||||
} = useFormContext();
|
} = useFormContext();
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
|
const convert = () =>
|
||||||
|
options.map((option) => (
|
||||||
|
<SelectOption
|
||||||
|
key={typeof option === "string" ? option : option.key}
|
||||||
|
value={typeof option === "string" ? option : option.key}
|
||||||
|
>
|
||||||
|
{typeof option === "string" ? option : option.value}
|
||||||
|
</SelectOption>
|
||||||
|
));
|
||||||
return (
|
return (
|
||||||
<FormLabel
|
<FormLabel
|
||||||
name={name}
|
name={name}
|
||||||
|
@ -98,20 +115,17 @@ export const SelectControl = <
|
||||||
}
|
}
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
|
onFilter={(_, value) => {
|
||||||
|
onFilter?.(value);
|
||||||
|
return convert();
|
||||||
|
}}
|
||||||
isOpen={open}
|
isOpen={open}
|
||||||
variant={variant}
|
variant={variant}
|
||||||
validated={
|
validated={
|
||||||
errors[name] ? ValidatedOptions.error : ValidatedOptions.default
|
errors[name] ? ValidatedOptions.error : ValidatedOptions.default
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{options.map((option) => (
|
{convert()}
|
||||||
<SelectOption
|
|
||||||
key={typeof option === "string" ? option : option.key}
|
|
||||||
value={typeof option === "string" ? option : option.key}
|
|
||||||
>
|
|
||||||
{typeof option === "string" ? option : option.value}
|
|
||||||
</SelectOption>
|
|
||||||
))}
|
|
||||||
</Select>
|
</Select>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
Loading…
Reference in a new issue