move keycloak select to ui-shared and fix typeahead (#30209)

* move keycloak select to ui-shared and fix typeahead

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* Fix the account console test

Signed-off-by: Hynek Mlnarik <hmlnarik@redhat.com>

* Fix cypress tests

Signed-off-by: Hynek Mlnarik <hmlnarik@redhat.com>

* fix for when value is an array

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* fix for when value is an array

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* add support for array selecting single value

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* fixed saying open once clicked outside and value

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* small issue when pressing enter

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

---------

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>
Signed-off-by: Hynek Mlnarik <hmlnarik@redhat.com>
Co-authored-by: Hynek Mlnarik <hmlnarik@redhat.com>
This commit is contained in:
Erik Jan de Wit 2024-06-07 18:05:03 +02:00 committed by GitHub
parent 28fd38d13d
commit d2e8092c7f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
48 changed files with 258 additions and 251 deletions

View file

@ -63,10 +63,10 @@ test.describe("Personal info with userprofile enabled", () => {
test("render long select options as typeahead", async ({ page }) => { test("render long select options as typeahead", async ({ page }) => {
await login(page, user, "jdoe", realm); await login(page, user, "jdoe", realm);
await page.getByText("Alternate Language").click(); await page.locator("#alternatelang").click();
await page.waitForSelector("text=Italiano"); await page.waitForSelector("text=Italiano");
await page.getByText("Alternate Language").click(); await page.locator("#alternatelang").click();
await page.locator("*:focus").press("Control+A"); await page.locator("*:focus").press("Control+A");
await page.locator("*:focus").pressSequentially("S"); await page.locator("*:focus").pressSequentially("S");
await expect(page.getByText("Italiano")).toHaveCount(0); await expect(page.getByText("Italiano")).toHaveCount(0);

View file

@ -9,8 +9,8 @@ export default defineConfig({
video: isCI, video: isCI,
projectId: "j4yhox", projectId: "j4yhox",
chromeWebSecurity: false, chromeWebSecurity: false,
viewportWidth: 1360, viewportWidth: 1920,
viewportHeight: 768, viewportHeight: 1200,
defaultCommandTimeout: 30000, defaultCommandTimeout: 30000,
numTestsKeptInMemory: 30, numTestsKeptInMemory: 30,
experimentalMemoryManagement: true, experimentalMemoryManagement: true,

View file

@ -371,7 +371,7 @@ describe("User profile tabs", () => {
createUserPage createUserPage
.goToCreateUser() .goToCreateUser()
.assertAttributeLabel(attrName, attrName) .assertAttributeLabel(attrName, attrName)
.assertAttributeSelect(attrName, supportedOptions, "Choose...") .assertAttributeSelect(attrName, supportedOptions, "Select an option")
.setUsername(userName) .setUsername(userName)
.setAttributeValueOnSelect(attrName, opt1) .setAttributeValueOnSelect(attrName, opt1)
.create() .create()

View file

@ -1,4 +1,5 @@
import type ResourceRepresentation from "@keycloak/keycloak-admin-client/lib/defs/resourceRepresentation"; import type ResourceRepresentation from "@keycloak/keycloak-admin-client/lib/defs/resourceRepresentation";
import { KeycloakSelect, SelectVariant } from "@keycloak/keycloak-ui-shared";
import { Button, SelectOption, TextInput } from "@patternfly/react-core"; import { Button, SelectOption, TextInput } from "@patternfly/react-core";
import { MinusCircleIcon, PlusCircleIcon } from "@patternfly/react-icons"; import { MinusCircleIcon, PlusCircleIcon } from "@patternfly/react-icons";
import { Table, Tbody, Td, Th, Thead, Tr } from "@patternfly/react-table"; import { Table, Tbody, Td, Th, Thead, Tr } from "@patternfly/react-table";
@ -6,14 +7,9 @@ import { camelCase } from "lodash-es";
import { useEffect, useMemo, useState } from "react"; import { useEffect, useMemo, useState } from "react";
import { Controller, useFieldArray, useFormContext } from "react-hook-form"; import { Controller, useFieldArray, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { defaultContextAttributes } from "../utils"; import { defaultContextAttributes } from "../utils";
import "./key-based-attribute-input.css"; import "./key-based-attribute-input.css";
import {
KeycloakSelect,
SelectVariant,
} from "../../components/select/KeycloakSelect";
export type AttributeType = { export type AttributeType = {
key?: string; key?: string;

View file

@ -3,6 +3,7 @@ import { DecisionStrategy } from "@keycloak/keycloak-admin-client/lib/defs/polic
import { import {
FormErrorText, FormErrorText,
HelpItem, HelpItem,
SelectVariant,
TextAreaControl, TextAreaControl,
TextControl, TextControl,
} from "@keycloak/keycloak-ui-shared"; } from "@keycloak/keycloak-ui-shared";
@ -39,7 +40,6 @@ import {
} from "../routes/PermissionDetails"; } from "../routes/PermissionDetails";
import { ResourcesPolicySelect } from "./ResourcesPolicySelect"; import { ResourcesPolicySelect } from "./ResourcesPolicySelect";
import { ScopeSelect } from "./ScopeSelect"; import { ScopeSelect } from "./ScopeSelect";
import { SelectVariant } from "../../components/select/KeycloakSelect";
type FormFields = PolicyRepresentation & { type FormFields = PolicyRepresentation & {
resourceType: string; resourceType: string;

View file

@ -26,7 +26,7 @@ import {
KeycloakSelect, KeycloakSelect,
SelectVariant, SelectVariant,
Variant, Variant,
} from "../../components/select/KeycloakSelect"; } from "@keycloak/keycloak-ui-shared";
import { useRealm } from "../../context/realm-context/RealmContext"; import { useRealm } from "../../context/realm-context/RealmContext";
import { useFetch } from "../../utils/useFetch"; import { useFetch } from "../../utils/useFetch";
import useToggle from "../../utils/useToggle"; import useToggle from "../../utils/useToggle";

View file

@ -1,15 +1,15 @@
import type ScopeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/scopeRepresentation"; import type ScopeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/scopeRepresentation";
import { HelpItem } from "@keycloak/keycloak-ui-shared"; import {
HelpItem,
KeycloakSelect,
SelectVariant,
} from "@keycloak/keycloak-ui-shared";
import { FormGroup, SelectOption } from "@patternfly/react-core"; import { FormGroup, SelectOption } from "@patternfly/react-core";
import { useState } from "react"; import { useState } from "react";
import { Controller, useFormContext } from "react-hook-form"; import { Controller, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useAdminClient } from "../../admin-client"; import { useAdminClient } from "../../admin-client";
import { KeycloakSpinner } from "../../components/keycloak-spinner/KeycloakSpinner"; import { KeycloakSpinner } from "../../components/keycloak-spinner/KeycloakSpinner";
import {
KeycloakSelect,
SelectVariant,
} from "../../components/select/KeycloakSelect";
import { useFetch } from "../../utils/useFetch"; import { useFetch } from "../../utils/useFetch";
type Scope = { type Scope = {

View file

@ -1,14 +1,11 @@
import type ScopeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/scopeRepresentation"; import type ScopeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/scopeRepresentation";
import { KeycloakSelect, SelectVariant } from "@keycloak/keycloak-ui-shared";
import { SelectOption } from "@patternfly/react-core";
import { useRef, useState } from "react"; import { useRef, useState } from "react";
import { Controller, useFormContext } from "react-hook-form"; import { Controller, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useAdminClient } from "../../admin-client"; import { useAdminClient } from "../../admin-client";
import { useFetch } from "../../utils/useFetch"; import { useFetch } from "../../utils/useFetch";
import {
KeycloakSelect,
SelectVariant,
} from "../../components/select/KeycloakSelect";
import { SelectOption } from "@patternfly/react-core";
type ScopeSelectProps = { type ScopeSelectProps = {
clientId: string; clientId: string;

View file

@ -1,4 +1,5 @@
import type ClientScopeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientScopeRepresentation"; import type ClientScopeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientScopeRepresentation";
import { KeycloakSelect } from "@keycloak/keycloak-ui-shared";
import { import {
Button, Button,
ButtonVariant, ButtonVariant,
@ -17,7 +18,6 @@ import {
} from "@patternfly/react-icons"; } from "@patternfly/react-icons";
import { useMemo, useState } from "react"; import { useMemo, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { import {
ClientScopeType, ClientScopeType,
clientScopeTypesDropdown, clientScopeTypesDropdown,
@ -26,7 +26,6 @@ import { ListEmptyState } from "../../components/list-empty-state/ListEmptyState
import { KeycloakDataTable } from "../../components/table-toolbar/KeycloakDataTable"; import { KeycloakDataTable } from "../../components/table-toolbar/KeycloakDataTable";
import useToggle from "../../utils/useToggle"; import useToggle from "../../utils/useToggle";
import { getProtocolName } from "../utils"; import { getProtocolName } from "../utils";
import { KeycloakSelect } from "../../components/select/KeycloakSelect";
import "./client-scopes.css"; import "./client-scopes.css";

View file

@ -2,6 +2,12 @@ import type ClientScopeRepresentation from "@keycloak/keycloak-admin-client/lib/
import type ProtocolMapperRepresentation from "@keycloak/keycloak-admin-client/lib/defs/protocolMapperRepresentation"; import type ProtocolMapperRepresentation from "@keycloak/keycloak-admin-client/lib/defs/protocolMapperRepresentation";
import type RoleRepresentation from "@keycloak/keycloak-admin-client/lib/defs/roleRepresentation"; import type RoleRepresentation from "@keycloak/keycloak-admin-client/lib/defs/roleRepresentation";
import type { ProtocolMapperTypeRepresentation } from "@keycloak/keycloak-admin-client/lib/defs/serverInfoRepesentation"; import type { ProtocolMapperTypeRepresentation } from "@keycloak/keycloak-admin-client/lib/defs/serverInfoRepesentation";
import {
HelpItem,
KeycloakSelect,
SelectVariant,
useHelp,
} from "@keycloak/keycloak-ui-shared";
import { import {
ClipboardCopy, ClipboardCopy,
Form, Form,
@ -23,7 +29,6 @@ import { QuestionCircleIcon } from "@patternfly/react-icons";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { FormProvider, useForm } from "react-hook-form"; import { FormProvider, useForm } from "react-hook-form";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { HelpItem, useHelp } from "@keycloak/keycloak-ui-shared";
import { useAdminClient } from "../../admin-client"; import { useAdminClient } from "../../admin-client";
import { KeycloakDataTable } from "../../components/table-toolbar/KeycloakDataTable"; import { KeycloakDataTable } from "../../components/table-toolbar/KeycloakDataTable";
import { UserSelect } from "../../components/users/UserSelect"; import { UserSelect } from "../../components/users/UserSelect";
@ -35,10 +40,6 @@ import { useFetch } from "../../utils/useFetch";
import { GeneratedCodeTab } from "./GeneratedCodeTab"; import { GeneratedCodeTab } from "./GeneratedCodeTab";
import "./evaluate.css"; import "./evaluate.css";
import {
KeycloakSelect,
SelectVariant,
} from "../../components/select/KeycloakSelect";
export type EvaluateScopesProps = { export type EvaluateScopesProps = {
clientId: string; clientId: string;

View file

@ -1,11 +1,14 @@
import { HelpItem } from "@keycloak/keycloak-ui-shared"; import {
HelpItem,
KeycloakSelect,
SelectVariant,
} from "@keycloak/keycloak-ui-shared";
import { FormGroup, SelectOption } from "@patternfly/react-core"; import { FormGroup, SelectOption } from "@patternfly/react-core";
import { useState } from "react"; import { useState } from "react";
import { Controller, useFormContext } from "react-hook-form"; import { Controller, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { convertToName } from "./DynamicComponents"; import { convertToName } from "./DynamicComponents";
import type { ComponentProps } from "./components"; import type { ComponentProps } from "./components";
import { KeycloakSelect, SelectVariant } from "../select/KeycloakSelect";
export const ListComponent = ({ export const ListComponent = ({
name, name,

View file

@ -1,9 +1,12 @@
import { HelpItem } from "@keycloak/keycloak-ui-shared"; import {
HelpItem,
KeycloakSelect,
SelectVariant,
} from "@keycloak/keycloak-ui-shared";
import { FormGroup, SelectOption } from "@patternfly/react-core"; import { FormGroup, SelectOption } from "@patternfly/react-core";
import { useState } from "react"; import { useState } from "react";
import { Controller, useFormContext } from "react-hook-form"; import { Controller, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { KeycloakSelect, SelectVariant } from "../select/KeycloakSelect";
import { convertToName } from "./DynamicComponents"; import { convertToName } from "./DynamicComponents";
import type { ComponentProps } from "./components"; import type { ComponentProps } from "./components";

View file

@ -1,3 +1,4 @@
import { KeycloakSelect } from "@keycloak/keycloak-ui-shared";
import { import {
Grid, Grid,
GridItem, GridItem,
@ -9,7 +10,6 @@ import { UseControllerProps, useController } from "react-hook-form";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import useToggle from "../../utils/useToggle"; import useToggle from "../../utils/useToggle";
import { DefaultValue } from "./KeyValueInput"; import { DefaultValue } from "./KeyValueInput";
import { KeycloakSelect } from "../select/KeycloakSelect";
type KeySelectProp = UseControllerProps & { type KeySelectProp = UseControllerProps & {
selectItems: DefaultValue[]; selectItems: DefaultValue[];

View file

@ -1,8 +1,8 @@
import { KeycloakSelect } from "@keycloak/keycloak-ui-shared";
import { SelectOption, TextInput } from "@patternfly/react-core"; import { SelectOption, TextInput } from "@patternfly/react-core";
import { useMemo, useState } from "react"; import { useMemo, useState } from "react";
import { UseControllerProps, useController } from "react-hook-form"; import { UseControllerProps, useController } from "react-hook-form";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { KeycloakSelect } from "../select/KeycloakSelect";
import { DefaultValue } from "./KeyValueInput"; import { DefaultValue } from "./KeyValueInput";
type ValueSelectProps = UseControllerProps & { type ValueSelectProps = UseControllerProps & {

View file

@ -1,5 +1,8 @@
import { useEffect, useMemo, useState } from "react"; import {
import { useTranslation } from "react-i18next"; KeycloakSelect,
KeycloakSelectProps,
SelectVariant,
} from "@keycloak/keycloak-ui-shared";
import { import {
SelectOption, SelectOption,
Split, Split,
@ -7,11 +10,8 @@ import {
TextInput, TextInput,
TextInputProps, TextInputProps,
} from "@patternfly/react-core"; } from "@patternfly/react-core";
import { import { useEffect, useMemo, useState } from "react";
KeycloakSelect, import { useTranslation } from "react-i18next";
KeycloakSelectProps,
SelectVariant,
} from "../select/KeycloakSelect";
export type Unit = "second" | "minute" | "hour" | "day"; export type Unit = "second" | "minute" | "hour" | "day";

View file

@ -1,4 +1,9 @@
import type { UserProfileConfig } from "@keycloak/keycloak-admin-client/lib/defs/userProfileMetadata"; import type { UserProfileConfig } from "@keycloak/keycloak-admin-client/lib/defs/userProfileMetadata";
import {
KeycloakSelect,
SelectVariant,
label,
} from "@keycloak/keycloak-ui-shared";
import { import {
ActionGroup, ActionGroup,
Alert, Alert,
@ -18,11 +23,8 @@ import { ReactNode, useState } from "react";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Form } from "react-router-dom"; import { Form } from "react-router-dom";
import { SelectVariant, label } from "@keycloak/keycloak-ui-shared";
import { useAlerts } from "../alert/Alerts"; import { useAlerts } from "../alert/Alerts";
import { UserAttribute } from "./UserDataTable"; import { UserAttribute } from "./UserDataTable";
import { KeycloakSelect } from "../select/KeycloakSelect";
type UserDataTableAttributeSearchFormProps = { type UserDataTableAttributeSearchFormProps = {
activeFilters: UserAttribute[]; activeFilters: UserAttribute[];

View file

@ -1,5 +1,9 @@
import type AdminEventRepresentation from "@keycloak/keycloak-admin-client/lib/defs/adminEventRepresentation"; import type AdminEventRepresentation from "@keycloak/keycloak-admin-client/lib/defs/adminEventRepresentation";
import { TextControl } from "@keycloak/keycloak-ui-shared"; import {
KeycloakSelect,
SelectVariant,
TextControl,
} from "@keycloak/keycloak-ui-shared";
import { CodeEditor, Language } from "@patternfly/react-code-editor"; import { CodeEditor, Language } from "@patternfly/react-code-editor";
import { import {
ActionGroup, ActionGroup,
@ -32,10 +36,6 @@ import { useTranslation } from "react-i18next";
import { useAdminClient } from "../admin-client"; import { useAdminClient } from "../admin-client";
import DropdownPanel from "../components/dropdown-panel/DropdownPanel"; import DropdownPanel from "../components/dropdown-panel/DropdownPanel";
import { ListEmptyState } from "../components/list-empty-state/ListEmptyState"; import { ListEmptyState } from "../components/list-empty-state/ListEmptyState";
import {
KeycloakSelect,
SelectVariant,
} from "../components/select/KeycloakSelect";
import { import {
Action, Action,
KeycloakDataTable, KeycloakDataTable,

View file

@ -1,7 +1,11 @@
import type EventRepresentation from "@keycloak/keycloak-admin-client/lib/defs/eventRepresentation"; import type EventRepresentation from "@keycloak/keycloak-admin-client/lib/defs/eventRepresentation";
import type EventType from "@keycloak/keycloak-admin-client/lib/defs/eventTypes"; import type EventType from "@keycloak/keycloak-admin-client/lib/defs/eventTypes";
import type { RealmEventsConfigRepresentation } from "@keycloak/keycloak-admin-client/lib/defs/realmEventsConfigRepresentation"; import type { RealmEventsConfigRepresentation } from "@keycloak/keycloak-admin-client/lib/defs/realmEventsConfigRepresentation";
import { TextControl } from "@keycloak/keycloak-ui-shared"; import {
KeycloakSelect,
SelectVariant,
TextControl,
} from "@keycloak/keycloak-ui-shared";
import { import {
ActionGroup, ActionGroup,
Button, Button,
@ -37,10 +41,6 @@ import {
RoutableTabs, RoutableTabs,
useRoutableTab, useRoutableTab,
} from "../components/routable-tabs/RoutableTabs"; } from "../components/routable-tabs/RoutableTabs";
import {
KeycloakSelect,
SelectVariant,
} from "../components/select/KeycloakSelect";
import { KeycloakDataTable } from "../components/table-toolbar/KeycloakDataTable"; import { KeycloakDataTable } from "../components/table-toolbar/KeycloakDataTable";
import { ViewHeader } from "../components/view-header/ViewHeader"; import { ViewHeader } from "../components/view-header/ViewHeader";
import { useRealm } from "../context/realm-context/RealmContext"; import { useRealm } from "../context/realm-context/RealmContext";

View file

@ -2,17 +2,15 @@ import type IdentityProviderMapperRepresentation from "@keycloak/keycloak-admin-
import type { IdentityProviderMapperTypeRepresentation } from "@keycloak/keycloak-admin-client/lib/defs/identityProviderMapperTypeRepresentation"; import type { IdentityProviderMapperTypeRepresentation } from "@keycloak/keycloak-admin-client/lib/defs/identityProviderMapperTypeRepresentation";
import { import {
HelpItem, HelpItem,
KeycloakSelect,
SelectControl, SelectControl,
SelectVariant,
TextControl, TextControl,
} from "@keycloak/keycloak-ui-shared"; } from "@keycloak/keycloak-ui-shared";
import { FormGroup, SelectOption } from "@patternfly/react-core"; import { FormGroup, SelectOption } from "@patternfly/react-core";
import { useState } from "react"; import { useState } from "react";
import { Controller, UseFormReturn } from "react-hook-form"; import { Controller, UseFormReturn } from "react-hook-form";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import {
KeycloakSelect,
SelectVariant,
} from "../../components/select/KeycloakSelect";
import type { IdPMapperRepresentationWithAttributes } from "./AddMapper"; import type { IdPMapperRepresentationWithAttributes } from "./AddMapper";
type AddMapperFormProps = { type AddMapperFormProps = {

View file

@ -3,7 +3,9 @@ import type IdentityProviderRepresentation from "@keycloak/keycloak-admin-client
import { import {
FormErrorText, FormErrorText,
HelpItem, HelpItem,
KeycloakSelect,
SelectControl, SelectControl,
SelectVariant,
} from "@keycloak/keycloak-ui-shared"; } from "@keycloak/keycloak-ui-shared";
import { import {
FormGroup, FormGroup,
@ -16,10 +18,6 @@ import { useState } from "react";
import { Controller, useFormContext, useWatch } from "react-hook-form"; import { Controller, useFormContext, useWatch } from "react-hook-form";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useAdminClient } from "../../admin-client"; import { useAdminClient } from "../../admin-client";
import {
KeycloakSelect,
SelectVariant,
} from "../../components/select/KeycloakSelect";
import { useFetch } from "../../utils/useFetch"; import { useFetch } from "../../utils/useFetch";
import useIsFeatureEnabled, { Feature } from "../../utils/useIsFeatureEnabled"; import useIsFeatureEnabled, { Feature } from "../../utils/useIsFeatureEnabled";
import type { FieldProps } from "../component/FormGroupField"; import type { FieldProps } from "../component/FormGroupField";

View file

@ -1,3 +1,8 @@
import {
HelpItem,
KeycloakSelect,
SelectVariant,
} from "@keycloak/keycloak-ui-shared";
import { import {
ExpandableSection, ExpandableSection,
Form, Form,
@ -8,9 +13,6 @@ import {
import { useState } from "react"; import { useState } from "react";
import { Controller, useFormContext } from "react-hook-form"; import { Controller, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { HelpItem, SelectVariant } from "@keycloak/keycloak-ui-shared";
import { KeycloakSelect } from "../../components/select/KeycloakSelect";
import { FormGroupField } from "../component/FormGroupField"; import { FormGroupField } from "../component/FormGroupField";
import { SwitchField } from "../component/SwitchField"; import { SwitchField } from "../component/SwitchField";
import { TextField } from "../component/TextField"; import { TextField } from "../component/TextField";

View file

@ -1,18 +1,17 @@
import {
HelpItem,
KeycloakSelect,
SelectVariant,
} from "@keycloak/keycloak-ui-shared";
import { FormGroup, SelectOption } from "@patternfly/react-core"; import { FormGroup, SelectOption } from "@patternfly/react-core";
import { useState } from "react"; import { useState } from "react";
import { Controller, useFormContext, useWatch } from "react-hook-form"; import { Controller, useFormContext, useWatch } from "react-hook-form";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useServerInfo } from "../../context/server-info/ServerInfoProvider";
import { HelpItem } from "@keycloak/keycloak-ui-shared"; import { sortProviders } from "../../util";
import { ClientIdSecret } from "../component/ClientIdSecret"; import { ClientIdSecret } from "../component/ClientIdSecret";
import { SwitchField } from "../component/SwitchField"; import { SwitchField } from "../component/SwitchField";
import { sortProviders } from "../../util";
import { useServerInfo } from "../../context/server-info/ServerInfoProvider";
import { TextField } from "../component/TextField"; import { TextField } from "../component/TextField";
import {
KeycloakSelect,
SelectVariant,
} from "../../components/select/KeycloakSelect";
const clientAuthentications = [ const clientAuthentications = [
"client_secret_post", "client_secret_post",

View file

@ -1,11 +1,13 @@
import {
HelpItem,
KeycloakSelect,
SelectVariant,
} from "@keycloak/keycloak-ui-shared";
import { FormGroup, SelectOption } from "@patternfly/react-core"; import { FormGroup, SelectOption } from "@patternfly/react-core";
import { useState } from "react"; import { useState } from "react";
import { Controller, useFormContext } from "react-hook-form"; import { Controller, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { HelpItem, SelectVariant } from "@keycloak/keycloak-ui-shared";
import { MultiLineInput } from "../../components/multi-line-input/MultiLineInput"; import { MultiLineInput } from "../../components/multi-line-input/MultiLineInput";
import { KeycloakSelect } from "../../components/select/KeycloakSelect";
const comparisonValues = ["exact", "minimum", "maximum", "better"]; const comparisonValues = ["exact", "minimum", "maximum", "better"];

View file

@ -1,7 +1,11 @@
import type { ConfigPropertyRepresentation } from "@keycloak/keycloak-admin-client/lib/defs/authenticatorConfigInfoRepresentation"; import type { ConfigPropertyRepresentation } from "@keycloak/keycloak-admin-client/lib/defs/authenticatorConfigInfoRepresentation";
import type ClientProfileRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientProfileRepresentation"; import type ClientProfileRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientProfileRepresentation";
import type ComponentTypeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentTypeRepresentation"; import type ComponentTypeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentTypeRepresentation";
import { HelpItem } from "@keycloak/keycloak-ui-shared"; import {
HelpItem,
KeycloakSelect,
SelectVariant,
} from "@keycloak/keycloak-ui-shared";
import { import {
ActionGroup, ActionGroup,
AlertVariant, AlertVariant,
@ -18,10 +22,6 @@ import { useAdminClient } from "../admin-client";
import { useAlerts } from "../components/alert/Alerts"; import { useAlerts } from "../components/alert/Alerts";
import { DynamicComponents } from "../components/dynamic/DynamicComponents"; import { DynamicComponents } from "../components/dynamic/DynamicComponents";
import { FormAccess } from "../components/form/FormAccess"; import { FormAccess } from "../components/form/FormAccess";
import {
KeycloakSelect,
SelectVariant,
} from "../components/select/KeycloakSelect";
import { ViewHeader } from "../components/view-header/ViewHeader"; import { ViewHeader } from "../components/view-header/ViewHeader";
import { useServerInfo } from "../context/server-info/ServerInfoProvider"; import { useServerInfo } from "../context/server-info/ServerInfoProvider";
import { useFetch } from "../utils/useFetch"; import { useFetch } from "../utils/useFetch";

View file

@ -2,7 +2,11 @@ import type { ConfigPropertyRepresentation } from "@keycloak/keycloak-admin-clie
import type ClientPolicyConditionRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientPolicyConditionRepresentation"; import type ClientPolicyConditionRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientPolicyConditionRepresentation";
import type ClientPolicyRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientPolicyRepresentation"; import type ClientPolicyRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientPolicyRepresentation";
import type ComponentTypeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentTypeRepresentation"; import type ComponentTypeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentTypeRepresentation";
import { HelpItem } from "@keycloak/keycloak-ui-shared"; import {
HelpItem,
KeycloakSelect,
SelectVariant,
} from "@keycloak/keycloak-ui-shared";
import { import {
ActionGroup, ActionGroup,
AlertVariant, AlertVariant,
@ -20,10 +24,6 @@ import { useAdminClient } from "../admin-client";
import { useAlerts } from "../components/alert/Alerts"; import { useAlerts } from "../components/alert/Alerts";
import { DynamicComponents } from "../components/dynamic/DynamicComponents"; import { DynamicComponents } from "../components/dynamic/DynamicComponents";
import { FormAccess } from "../components/form/FormAccess"; import { FormAccess } from "../components/form/FormAccess";
import {
KeycloakSelect,
SelectVariant,
} from "../components/select/KeycloakSelect";
import { ViewHeader } from "../components/view-header/ViewHeader"; import { ViewHeader } from "../components/view-header/ViewHeader";
import { useRealm } from "../context/realm-context/RealmContext"; import { useRealm } from "../context/realm-context/RealmContext";
import { useServerInfo } from "../context/server-info/ServerInfoProvider"; import { useServerInfo } from "../context/server-info/ServerInfoProvider";

View file

@ -5,6 +5,7 @@ import type {
PartialImportResult, PartialImportResult,
} from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation"; } from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation";
import type RoleRepresentation from "@keycloak/keycloak-admin-client/lib/defs/roleRepresentation"; import type RoleRepresentation from "@keycloak/keycloak-admin-client/lib/defs/roleRepresentation";
import { KeycloakSelect } from "@keycloak/keycloak-ui-shared";
import { import {
Alert, Alert,
Button, Button,
@ -30,7 +31,6 @@ import { useTranslation } from "react-i18next";
import { useAdminClient } from "../admin-client"; import { useAdminClient } from "../admin-client";
import { useAlerts } from "../components/alert/Alerts"; import { useAlerts } from "../components/alert/Alerts";
import { JsonFileUpload } from "../components/json-file-upload/JsonFileUpload"; import { JsonFileUpload } from "../components/json-file-upload/JsonFileUpload";
import { KeycloakSelect } from "../components/select/KeycloakSelect";
import { KeycloakDataTable } from "../components/table-toolbar/KeycloakDataTable"; import { KeycloakDataTable } from "../components/table-toolbar/KeycloakDataTable";
import { useRealm } from "../context/realm-context/RealmContext"; import { useRealm } from "../context/realm-context/RealmContext";

View file

@ -1,4 +1,9 @@
import type RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation"; import type RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation";
import {
HelpItem,
KeycloakSelect,
SelectVariant,
} from "@keycloak/keycloak-ui-shared";
import { import {
ActionGroup, ActionGroup,
Button, Button,
@ -9,13 +14,7 @@ import {
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { Controller, useForm } from "react-hook-form"; import { Controller, useForm } from "react-hook-form";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { HelpItem } from "@keycloak/keycloak-ui-shared";
import { FormAccess } from "../components/form/FormAccess"; import { FormAccess } from "../components/form/FormAccess";
import {
KeycloakSelect,
SelectVariant,
} from "../components/select/KeycloakSelect";
import { useServerInfo } from "../context/server-info/ServerInfoProvider"; import { useServerInfo } from "../context/server-info/ServerInfoProvider";
import { convertToFormValues } from "../util"; import { convertToFormValues } from "../util";

View file

@ -1,4 +1,10 @@
import type RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation"; import type RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation";
import {
FormPanel,
HelpItem,
KeycloakSelect,
SelectVariant,
} from "@keycloak/keycloak-ui-shared";
import { import {
ActionGroup, ActionGroup,
Button, Button,
@ -17,8 +23,6 @@ import {
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { Controller, useForm, useWatch } from "react-hook-form"; import { Controller, useForm, useWatch } from "react-hook-form";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { FormPanel, HelpItem } from "@keycloak/keycloak-ui-shared";
import { FormAccess } from "../components/form/FormAccess"; import { FormAccess } from "../components/form/FormAccess";
import { import {
TimeSelector, TimeSelector,
@ -30,10 +34,6 @@ import { beerify, convertToFormValues, sortProviders } from "../util";
import useIsFeatureEnabled, { Feature } from "../utils/useIsFeatureEnabled"; import useIsFeatureEnabled, { Feature } from "../utils/useIsFeatureEnabled";
import "./realm-settings-section.css"; import "./realm-settings-section.css";
import {
KeycloakSelect,
SelectVariant,
} from "../components/select/KeycloakSelect";
type RealmSettingsSessionsTabProps = { type RealmSettingsSessionsTabProps = {
realm: RealmRepresentation; realm: RealmRepresentation;

View file

@ -1,5 +1,6 @@
import type ComponentRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentRepresentation"; import type ComponentRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentRepresentation";
import type { KeyMetadataRepresentation } from "@keycloak/keycloak-admin-client/lib/defs/keyMetadataRepresentation"; import type { KeyMetadataRepresentation } from "@keycloak/keycloak-admin-client/lib/defs/keyMetadataRepresentation";
import { KeycloakSelect, SelectVariant } from "@keycloak/keycloak-ui-shared";
import { import {
Button, Button,
ButtonVariant, ButtonVariant,
@ -15,10 +16,6 @@ import { useAdminClient } from "../../admin-client";
import { useConfirmDialog } from "../../components/confirm-dialog/ConfirmDialog"; import { useConfirmDialog } from "../../components/confirm-dialog/ConfirmDialog";
import { KeycloakSpinner } from "../../components/keycloak-spinner/KeycloakSpinner"; import { KeycloakSpinner } from "../../components/keycloak-spinner/KeycloakSpinner";
import { ListEmptyState } from "../../components/list-empty-state/ListEmptyState"; import { ListEmptyState } from "../../components/list-empty-state/ListEmptyState";
import {
KeycloakSelect,
SelectVariant,
} from "../../components/select/KeycloakSelect";
import { KeycloakDataTable } from "../../components/table-toolbar/KeycloakDataTable"; import { KeycloakDataTable } from "../../components/table-toolbar/KeycloakDataTable";
import { useRealm } from "../../context/realm-context/RealmContext"; import { useRealm } from "../../context/realm-context/RealmContext";
import { emptyFormatter } from "../../util"; import { emptyFormatter } from "../../util";

View file

@ -1,3 +1,4 @@
import { KeycloakSelect, SelectVariant } from "@keycloak/keycloak-ui-shared";
import { import {
ActionGroup, ActionGroup,
Button, Button,
@ -28,10 +29,6 @@ import { useWhoAmI } from "../../context/whoami/WhoAmI";
import { DEFAULT_LOCALE } from "../../i18n/i18n"; import { DEFAULT_LOCALE } from "../../i18n/i18n";
import { localeToDisplayName } from "../../util"; import { localeToDisplayName } from "../../util";
import useLocaleSort, { mapByKey } from "../../utils/useLocaleSort"; import useLocaleSort, { mapByKey } from "../../utils/useLocaleSort";
import {
KeycloakSelect,
SelectVariant,
} from "../../components/select/KeycloakSelect";
type EffectiveMessageBundlesProps = { type EffectiveMessageBundlesProps = {
defaultSupportedLocales: string[]; defaultSupportedLocales: string[];

View file

@ -1,22 +1,23 @@
import type RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation"; import type RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation";
import { KeycloakSelect, SelectVariant } from "@keycloak/keycloak-ui-shared";
import { import {
AlertVariant, AlertVariant,
Button, Button,
ButtonVariant, ButtonVariant,
Divider, Divider,
Dropdown,
DropdownItem,
DropdownList,
Form, Form,
FormGroup, FormGroup,
MenuToggle,
SelectGroup,
SelectOption,
Text, Text,
TextContent, TextContent,
TextInput, TextInput,
TextVariants, TextVariants,
ToolbarItem, ToolbarItem,
SelectGroup,
SelectOption,
Dropdown,
MenuToggle,
DropdownList,
DropdownItem,
} from "@patternfly/react-core"; } from "@patternfly/react-core";
import { import {
CheckIcon, CheckIcon,
@ -51,10 +52,6 @@ import { useWhoAmI } from "../../context/whoami/WhoAmI";
import { DEFAULT_LOCALE } from "../../i18n/i18n"; import { DEFAULT_LOCALE } from "../../i18n/i18n";
import { localeToDisplayName } from "../../util"; import { localeToDisplayName } from "../../util";
import { AddTranslationModal } from "../AddTranslationModal"; import { AddTranslationModal } from "../AddTranslationModal";
import {
KeycloakSelect,
SelectVariant,
} from "../../components/select/KeycloakSelect";
type RealmOverridesProps = { type RealmOverridesProps = {
internationalizationEnabled: boolean; internationalizationEnabled: boolean;

View file

@ -1,4 +1,10 @@
import type RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation"; import type RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation";
import {
HelpItem,
KeycloakSelect,
NumberControl,
SelectVariant,
} from "@keycloak/keycloak-ui-shared";
import { import {
ActionGroup, ActionGroup,
Button, Button,
@ -8,14 +14,9 @@ import {
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { FormProvider, useForm } from "react-hook-form"; import { FormProvider, useForm } from "react-hook-form";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { HelpItem, NumberControl } from "@keycloak/keycloak-ui-shared";
import { FormAccess } from "../../components/form/FormAccess"; import { FormAccess } from "../../components/form/FormAccess";
import { convertToFormValues } from "../../util"; import { convertToFormValues } from "../../util";
import { Time } from "./Time"; import { Time } from "./Time";
import {
KeycloakSelect,
SelectVariant,
} from "../../components/select/KeycloakSelect";
type BruteForceDetectionProps = { type BruteForceDetectionProps = {
realm: RealmRepresentation; realm: RealmRepresentation;

View file

@ -1,4 +1,5 @@
import type { UserProfileAttribute } from "@keycloak/keycloak-admin-client/lib/defs/userProfileMetadata"; import type { UserProfileAttribute } from "@keycloak/keycloak-admin-client/lib/defs/userProfileMetadata";
import { KeycloakSelect, SelectVariant } from "@keycloak/keycloak-ui-shared";
import { import {
Button, Button,
ButtonVariant, ButtonVariant,
@ -13,20 +14,16 @@ import { uniqBy } from "lodash-es";
import { useState } from "react"; import { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Link, useNavigate } from "react-router-dom"; import { Link, useNavigate } from "react-router-dom";
import { useAdminClient } from "../../admin-client";
import { DraggableTable } from "../../authentication/components/DraggableTable"; import { DraggableTable } from "../../authentication/components/DraggableTable";
import { useConfirmDialog } from "../../components/confirm-dialog/ConfirmDialog"; import { useConfirmDialog } from "../../components/confirm-dialog/ConfirmDialog";
import { KeycloakSpinner } from "../../components/keycloak-spinner/KeycloakSpinner"; import { KeycloakSpinner } from "../../components/keycloak-spinner/KeycloakSpinner";
import { useRealm } from "../../context/realm-context/RealmContext"; import { useRealm } from "../../context/realm-context/RealmContext";
import useLocale from "../../utils/useLocale";
import useToggle from "../../utils/useToggle"; import useToggle from "../../utils/useToggle";
import { toAddAttribute } from "../routes/AddAttribute"; import { toAddAttribute } from "../routes/AddAttribute";
import { toAttribute } from "../routes/Attribute"; import { toAttribute } from "../routes/Attribute";
import { useUserProfile } from "./UserProfileContext"; import { useUserProfile } from "./UserProfileContext";
import useLocale from "../../utils/useLocale";
import { useAdminClient } from "../../admin-client";
import {
KeycloakSelect,
SelectVariant,
} from "../../components/select/KeycloakSelect";
const RESTRICTED_ATTRIBUTES = ["username", "email"]; const RESTRICTED_ATTRIBUTES = ["username", "email"];

View file

@ -3,7 +3,9 @@ import type { UserProfileConfig } from "@keycloak/keycloak-admin-client/lib/defs
import { import {
FormErrorText, FormErrorText,
HelpItem, HelpItem,
KeycloakSelect,
SelectControl, SelectControl,
SelectVariant,
} from "@keycloak/keycloak-ui-shared"; } from "@keycloak/keycloak-ui-shared";
import { import {
Alert, Alert,
@ -30,10 +32,6 @@ import { useTranslation } from "react-i18next";
import { useAdminClient } from "../../../admin-client"; import { useAdminClient } from "../../../admin-client";
import { FormAccess } from "../../../components/form/FormAccess"; import { FormAccess } from "../../../components/form/FormAccess";
import { KeycloakSpinner } from "../../../components/keycloak-spinner/KeycloakSpinner"; import { KeycloakSpinner } from "../../../components/keycloak-spinner/KeycloakSpinner";
import {
KeycloakSelect,
SelectVariant,
} from "../../../components/select/KeycloakSelect";
import { useRealm } from "../../../context/realm-context/RealmContext"; import { useRealm } from "../../../context/realm-context/RealmContext";
import { useFetch } from "../../../utils/useFetch"; import { useFetch } from "../../../utils/useFetch";
import { useParams } from "../../../utils/useParams"; import { useParams } from "../../../utils/useParams";

View file

@ -1,8 +1,8 @@
import ComponentTypeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentTypeRepresentation"; import ComponentTypeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentTypeRepresentation";
import { KeycloakSelect } from "@keycloak/keycloak-ui-shared";
import { FormGroup, SelectOption } from "@patternfly/react-core"; import { FormGroup, SelectOption } from "@patternfly/react-core";
import { useMemo, useState } from "react"; import { useMemo, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { KeycloakSelect } from "../../../components/select/KeycloakSelect";
import { useServerInfo } from "../../../context/server-info/ServerInfoProvider"; import { useServerInfo } from "../../../context/server-info/ServerInfoProvider";
import useToggle from "../../../utils/useToggle"; import useToggle from "../../../utils/useToggle";

View file

@ -1,4 +1,5 @@
import UserSessionRepresentation from "@keycloak/keycloak-admin-client/lib/defs/userSessionRepresentation"; import UserSessionRepresentation from "@keycloak/keycloak-admin-client/lib/defs/userSessionRepresentation";
import { KeycloakSelect } from "@keycloak/keycloak-ui-shared";
import { import {
DropdownItem, DropdownItem,
PageSection, PageSection,
@ -10,7 +11,6 @@ import { useTranslation } from "react-i18next";
import { useAdminClient } from "../admin-client"; import { useAdminClient } from "../admin-client";
import { useAlerts } from "../components/alert/Alerts"; import { useAlerts } from "../components/alert/Alerts";
import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog"; import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog";
import { KeycloakSelect } from "../components/select/KeycloakSelect";
import { ViewHeader } from "../components/view-header/ViewHeader"; import { ViewHeader } from "../components/view-header/ViewHeader";
import { fetchAdminUI } from "../context/auth/admin-ui-endpoint"; import { fetchAdminUI } from "../context/auth/admin-ui-endpoint";
import { useRealm } from "../context/realm-context/RealmContext"; import { useRealm } from "../context/realm-context/RealmContext";

View file

@ -1,4 +1,12 @@
import type TestLdapConnectionRepresentation from "@keycloak/keycloak-admin-client/lib/defs/testLdapConnection"; import type TestLdapConnectionRepresentation from "@keycloak/keycloak-admin-client/lib/defs/testLdapConnection";
import {
HelpItem,
KeycloakSelect,
PasswordControl,
SelectControl,
SelectVariant,
TextControl,
} from "@keycloak/keycloak-ui-shared";
import { import {
AlertVariant, AlertVariant,
Button, Button,
@ -15,21 +23,11 @@ import {
useWatch, useWatch,
} from "react-hook-form"; } from "react-hook-form";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import {
HelpItem,
PasswordControl,
SelectControl,
TextControl,
} from "@keycloak/keycloak-ui-shared";
import { useAdminClient } from "../../admin-client"; import { useAdminClient } from "../../admin-client";
import { useAlerts } from "../../components/alert/Alerts"; import { useAlerts } from "../../components/alert/Alerts";
import { FormAccess } from "../../components/form/FormAccess"; import { FormAccess } from "../../components/form/FormAccess";
import { WizardSectionHeader } from "../../components/wizard-section-header/WizardSectionHeader"; import { WizardSectionHeader } from "../../components/wizard-section-header/WizardSectionHeader";
import { useRealm } from "../../context/realm-context/RealmContext"; import { useRealm } from "../../context/realm-context/RealmContext";
import {
KeycloakSelect,
SelectVariant,
} from "../../components/select/KeycloakSelect";
export type LdapSettingsConnectionProps = { export type LdapSettingsConnectionProps = {
form: UseFormReturn; form: UseFormReturn;

View file

@ -1,16 +1,17 @@
import ComponentRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentRepresentation"; import ComponentRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentRepresentation";
import {
HelpItem,
KeycloakSelect,
SelectVariant,
TextControl,
} from "@keycloak/keycloak-ui-shared";
import { FormGroup, SelectOption } from "@patternfly/react-core"; import { FormGroup, SelectOption } from "@patternfly/react-core";
import { HelpItem, TextControl } from "@keycloak/keycloak-ui-shared";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { Controller, FormProvider, UseFormReturn } from "react-hook-form"; import { Controller, FormProvider, UseFormReturn } from "react-hook-form";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { FormAccess } from "../../components/form/FormAccess"; import { FormAccess } from "../../components/form/FormAccess";
import { WizardSectionHeader } from "../../components/wizard-section-header/WizardSectionHeader"; import { WizardSectionHeader } from "../../components/wizard-section-header/WizardSectionHeader";
import { useRealm } from "../../context/realm-context/RealmContext"; import { useRealm } from "../../context/realm-context/RealmContext";
import {
KeycloakSelect,
SelectVariant,
} from "../../components/select/KeycloakSelect";
export type LdapSettingsGeneralProps = { export type LdapSettingsGeneralProps = {
form: UseFormReturn<ComponentRepresentation>; form: UseFormReturn<ComponentRepresentation>;

View file

@ -1,6 +1,12 @@
import type ComponentRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentRepresentation"; import type ComponentRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentRepresentation";
import type ComponentTypeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentTypeRepresentation"; import type ComponentTypeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentTypeRepresentation";
import { DirectionType } from "@keycloak/keycloak-admin-client/lib/resources/userStorageProvider"; import { DirectionType } from "@keycloak/keycloak-admin-client/lib/resources/userStorageProvider";
import {
HelpItem,
KeycloakSelect,
SelectVariant,
TextControl,
} from "@keycloak/keycloak-ui-shared";
import { import {
ActionGroup, ActionGroup,
AlertVariant, AlertVariant,
@ -15,7 +21,6 @@ import { useState } from "react";
import { Controller, FormProvider, useForm, useWatch } from "react-hook-form"; import { Controller, FormProvider, useForm, useWatch } from "react-hook-form";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { HelpItem, TextControl } from "@keycloak/keycloak-ui-shared";
import { useAdminClient } from "../../../admin-client"; import { useAdminClient } from "../../../admin-client";
import { useAlerts } from "../../../components/alert/Alerts"; import { useAlerts } from "../../../components/alert/Alerts";
import { useConfirmDialog } from "../../../components/confirm-dialog/ConfirmDialog"; import { useConfirmDialog } from "../../../components/confirm-dialog/ConfirmDialog";
@ -32,10 +37,6 @@ import { useFetch } from "../../../utils/useFetch";
import { useParams } from "../../../utils/useParams"; import { useParams } from "../../../utils/useParams";
import { toUserFederationLdap } from "../../routes/UserFederationLdap"; import { toUserFederationLdap } from "../../routes/UserFederationLdap";
import { UserFederationLdapMapperParams } from "../../routes/UserFederationLdapMapper"; import { UserFederationLdapMapperParams } from "../../routes/UserFederationLdapMapper";
import {
KeycloakSelect,
SelectVariant,
} from "../../../components/select/KeycloakSelect";
export default function LdapMapperDetails() { export default function LdapMapperDetails() {
const { adminClient } = useAdminClient(); const { adminClient } = useAdminClient();

View file

@ -1,15 +1,16 @@
import {
HelpItem,
KeycloakSelect,
SelectControl,
SelectVariant,
} from "@keycloak/keycloak-ui-shared";
import { FormGroup, NumberInput, SelectOption } from "@patternfly/react-core"; import { FormGroup, NumberInput, SelectOption } from "@patternfly/react-core";
import { isEqual } from "lodash-es"; import { isEqual } from "lodash-es";
import { Controller, UseFormReturn, useWatch } from "react-hook-form"; import { Controller, UseFormReturn, useWatch } from "react-hook-form";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { FormAccess } from "../../components/form/FormAccess"; import { FormAccess } from "../../components/form/FormAccess";
import { HelpItem, SelectControl } from "@keycloak/keycloak-ui-shared";
import { WizardSectionHeader } from "../../components/wizard-section-header/WizardSectionHeader"; import { WizardSectionHeader } from "../../components/wizard-section-header/WizardSectionHeader";
import useToggle from "../../utils/useToggle"; import useToggle from "../../utils/useToggle";
import {
KeycloakSelect,
SelectVariant,
} from "../../components/select/KeycloakSelect";
export type SettingsCacheProps = { export type SettingsCacheProps = {
form: UseFormReturn; form: UseFormReturn;

View file

@ -1,3 +1,4 @@
import { KeycloakSelect } from "@keycloak/keycloak-ui-shared";
import { import {
Dropdown, Dropdown,
DropdownItem, DropdownItem,
@ -9,7 +10,6 @@ import {
import { FilterIcon } from "@patternfly/react-icons"; import { FilterIcon } from "@patternfly/react-icons";
import { useState } from "react"; import { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { KeycloakSelect } from "../../components/select/KeycloakSelect";
export type SearchType = "default" | "attribute"; export type SearchType = "default" | "attribute";

View file

@ -39,13 +39,6 @@ export const SingleSelectControl = <
} = useFormContext(); } = useFormContext();
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const convert = () =>
options.map((option) => (
<SelectOption key={key(option)} value={key(option)}>
{isString(option) ? option : option.value}
</SelectOption>
));
return ( return (
<FormLabel <FormLabel
name={name} name={name}
@ -62,6 +55,7 @@ export const SingleSelectControl = <
<Select <Select
{...rest} {...rest}
onClick={() => setOpen(!open)} onClick={() => setOpen(!open)}
onOpenChange={() => setOpen(false)}
selected={ selected={
isSelectBasedOptions(options) isSelectBasedOptions(options)
? options ? options
@ -84,28 +78,27 @@ export const SingleSelectControl = <
aria-label="toggle" aria-label="toggle"
> >
{isSelectBasedOptions(options) {isSelectBasedOptions(options)
? options.find((o) => o.key === value)?.value ? options.find(
(o) =>
o.key === (Array.isArray(value) ? value[0] : value),
)?.value
: value} : value}
</MenuToggle> </MenuToggle>
)} )}
onSelect={(event, v) => { onSelect={(_event, v) => {
event?.stopPropagation(); const option = v?.toString();
if (Array.isArray(value)) { onChange(Array.isArray(value) ? [option] : option);
const option = v?.toString(); setOpen(false);
const selected = key(option!);
if (value.includes(key)) {
onChange(value.filter((item: string) => item !== selected));
} else {
onChange([...value, option]);
}
} else {
onChange(v);
setOpen(false);
}
}} }}
isOpen={open} isOpen={open}
> >
<SelectList>{convert()}</SelectList> <SelectList>
{options.map((option) => (
<SelectOption key={key(option)} value={key(option)}>
{isString(option) ? option : option.value}
</SelectOption>
))}
</SelectList>
</Select> </Select>
)} )}
/> />

View file

@ -89,11 +89,14 @@ export const TypeaheadSelectControl = <
if (variant !== SelectVariant.typeaheadMulti) { if (variant !== SelectVariant.typeaheadMulti) {
setFilterValue(getValue(focusedItem)); setFilterValue(getValue(focusedItem));
} else {
setFilterValue("");
} }
field.onChange( field.onChange(
Array.isArray(field.value) Array.isArray(field.value)
? [...field.value, getValue(focusedItem)] ? [...field.value, key(focusedItem)]
: getValue(focusedItem), : key(focusedItem),
); );
setOpen(false); setOpen(false);
setFocusedItemIndex(0); setFocusedItemIndex(0);
@ -106,6 +109,12 @@ export const TypeaheadSelectControl = <
field.onChange(undefined); field.onChange(undefined);
break; break;
} }
case "Backspace": {
if (variant === SelectVariant.typeahead) {
field.onChange("");
}
break;
}
case "ArrowUp": case "ArrowUp":
case "ArrowDown": { case "ArrowDown": {
event.preventDefault(); event.preventDefault();
@ -150,6 +159,7 @@ export const TypeaheadSelectControl = <
<Select <Select
{...rest} {...rest}
onClick={() => setOpen(!open)} onClick={() => setOpen(!open)}
onOpenChange={() => setOpen(false)}
selected={ selected={
isSelectBasedOptions(options) isSelectBasedOptions(options)
? options ? options
@ -174,7 +184,19 @@ export const TypeaheadSelectControl = <
<TextInputGroup isPlain> <TextInputGroup isPlain>
<TextInputGroupMain <TextInputGroupMain
placeholder={placeholderText} placeholder={placeholderText}
value={filterValue} value={
variant === SelectVariant.typeahead && field.value
? isSelectBasedOptions(options)
? options.find(
(o) =>
o.key ===
(Array.isArray(field.value)
? field.value[0]
: field.value),
)?.value
: field.value
: filterValue
}
onClick={() => setOpen(!open)} onClick={() => setOpen(!open)}
onChange={(_, value) => { onChange={(_, value) => {
setFilterValue(value); setFilterValue(value);
@ -234,21 +256,19 @@ export const TypeaheadSelectControl = <
onSelect={(event, v) => { onSelect={(event, v) => {
event?.stopPropagation(); event?.stopPropagation();
const option = v?.toString(); const option = v?.toString();
if (Array.isArray(field.value)) { if (
const select = key(option!); variant === SelectVariant.typeaheadMulti &&
if (field.value.includes(key)) { Array.isArray(field.value)
) {
if (field.value.includes(option)) {
field.onChange( field.onChange(
field.value.filter((item: string) => item !== select), field.value.filter((item: string) => item !== option),
); );
} else { } else {
field.onChange([...field.value, option]); field.onChange([...field.value, option]);
} }
} else { } else {
const val = isSelectBasedOptions(options) field.onChange(Array.isArray(field.value) ? [option] : option);
? options.find((o) => o.key === option)?.value
: option;
field.onChange(val);
setFilterValue(val || "");
setOpen(false); setOpen(false);
} }
}} }}

View file

@ -58,3 +58,5 @@ export { isDefined } from "./utils/isDefined";
export { useRequiredContext } from "./utils/useRequiredContext"; export { useRequiredContext } from "./utils/useRequiredContext";
export { useStoredState } from "./utils/useStoredState"; export { useStoredState } from "./utils/useStoredState";
export { default as KeycloakMasthead } from "./masthead/Masthead"; export { default as KeycloakMasthead } from "./masthead/Masthead";
export { KeycloakSelect } from "./select/KeycloakSelect";
export type { Variant, KeycloakSelectProps } from "./select/KeycloakSelect";

View file

@ -54,6 +54,7 @@ export const SingleSelect = ({
}} }}
{...props} {...props}
onClick={toggle} onClick={toggle}
onOpenChange={() => setOpen(false)}
selected={selections} selected={selections}
onSelect={(_, value) => { onSelect={(_, value) => {
onSelect?.(value || ""); onSelect?.(value || "");

View file

@ -75,6 +75,12 @@ export const TypeaheadSelect = ({
onToggle?.(false); onToggle?.(false);
break; break;
} }
case "Backspace": {
if (variant === SelectVariant.typeahead) {
onSelect?.("");
}
break;
}
case "ArrowUp": case "ArrowUp":
case "ArrowDown": { case "ArrowDown": {
event.preventDefault(); event.preventDefault();
@ -107,6 +113,7 @@ export const TypeaheadSelect = ({
<Select <Select
{...rest} {...rest}
onClick={toggle} onClick={toggle}
onOpenChange={() => onToggle?.(false)}
onSelect={(_, value) => onSelect?.(value || "")} onSelect={(_, value) => onSelect?.(value || "")}
maxMenuHeight={propertyToString(maxHeight)} maxMenuHeight={propertyToString(maxHeight)}
popperProps={{ direction, width: propertyToString(width) }} popperProps={{ direction, width: propertyToString(width) }}
@ -124,7 +131,11 @@ export const TypeaheadSelect = ({
<TextInputGroup isPlain> <TextInputGroup isPlain>
<TextInputGroupMain <TextInputGroupMain
placeholder={placeholderText} placeholder={placeholderText}
value={filterValue} value={
variant === SelectVariant.typeahead && selections
? (selections as string)
: filterValue
}
onClick={toggle} onClick={toggle}
onChange={(_, value) => { onChange={(_, value) => {
setFilterValue(value); setFilterValue(value);
@ -165,6 +176,7 @@ export const TypeaheadSelect = ({
onClick={() => { onClick={() => {
onSelect?.(""); onSelect?.("");
setFilterValue(""); setFilterValue("");
onFilter?.("");
textInputRef?.current?.focus(); textInputRef?.current?.focus();
}} }}
aria-label="Clear input value" aria-label="Clear input value"

View file

@ -1,13 +1,7 @@
import { import { SelectOption } from "@patternfly/react-core";
Chip,
ChipGroup,
MenuToggle,
Select,
SelectList,
SelectOption,
} from "@patternfly/react-core";
import { useState } from "react"; import { useState } from "react";
import { Controller, ControllerRenderProps } from "react-hook-form"; import { Controller, ControllerRenderProps } from "react-hook-form";
import { KeycloakSelect, SelectVariant } from "../select/KeycloakSelect";
import { import {
OptionLabel, OptionLabel,
Options, Options,
@ -19,6 +13,7 @@ import { UserFormFields, fieldName, label } from "./utils";
export const SelectComponent = (props: UserProfileFieldProps) => { export const SelectComponent = (props: UserProfileFieldProps) => {
const { t, form, inputType, attribute } = props; const { t, form, inputType, attribute } = props;
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [filter, setFilter] = useState("");
const isMultiValue = inputType === "multiselect"; const isMultiValue = inputType === "multiselect";
const setValue = ( const setValue = (
@ -36,7 +31,7 @@ export const SelectComponent = (props: UserProfileFieldProps) => {
} }
} }
} else { } else {
field.onChange(value); field.onChange(value === field.value ? "" : value);
} }
}; };
@ -45,9 +40,25 @@ export const SelectComponent = (props: UserProfileFieldProps) => {
const optionLabel = const optionLabel =
(attribute.annotations?.["inputOptionLabels"] as OptionLabel) || {}; (attribute.annotations?.["inputOptionLabels"] as OptionLabel) || {};
const fetchLabel = (option: string) => const fetchLabel = (option: string) =>
label(props.t, optionLabel[option], option); label(props.t, optionLabel[option], option);
const convertOptions = (selected: string) =>
options
.filter((o) =>
fetchLabel(o)!.toLowerCase().includes(filter.toLowerCase()),
)
.map((option) => (
<SelectOption
selected={selected === option}
key={option}
value={option}
>
{fetchLabel(option)}
</SelectOption>
));
return ( return (
<UserProfileGroup {...props}> <UserProfileGroup {...props}>
<Controller <Controller
@ -55,58 +66,39 @@ export const SelectComponent = (props: UserProfileFieldProps) => {
defaultValue="" defaultValue=""
control={form.control} control={form.control}
render={({ field }) => ( render={({ field }) => (
<Select <KeycloakSelect
toggle={(ref) => ( toggleId={attribute.name}
<MenuToggle onToggle={(b) => setOpen(b)}
id={attribute.name} onClear={() => setValue("", field)}
ref={ref} onSelect={(value) => {
onClick={() => setOpen(!open)} const option = value.toString();
isExpanded={open}
isFullWidth
isDisabled={attribute.readOnly}
>
{(isMultiValue && Array.isArray(field.value) ? (
<ChipGroup>
{field.value.map((selection, index: number) => (
<Chip
key={index}
onClick={(ev) => {
ev.stopPropagation();
setValue(selection, field);
}}
>
{selection}
</Chip>
))}
</ChipGroup>
) : (
fetchLabel(field.value)
)) || t("choose")}
</MenuToggle>
)}
onSelect={(_, value) => {
const option = value?.toString() || "";
setValue(option, field); setValue(option, field);
if (!isMultiValue) { if (!Array.isArray(field.value)) {
setOpen(false); setOpen(false);
} }
}} }}
selected={field.value} selections={
isMultiValue && Array.isArray(field.value)
? field.value
: fetchLabel(field.value)
}
variant={
isMultiValue
? SelectVariant.typeaheadMulti
: options.length >= 10
? SelectVariant.typeahead
: SelectVariant.single
}
aria-label={t("selectOne")} aria-label={t("selectOne")}
isOpen={open} isOpen={open}
isDisabled={attribute.readOnly}
onFilter={(value) => {
setFilter(value);
return convertOptions(field.value);
}}
> >
<SelectList> {convertOptions(field.value)}
{options.map((option) => ( </KeycloakSelect>
<SelectOption
selected={field.value === option}
key={option}
value={option}
>
{fetchLabel(option)}
</SelectOption>
))}
</SelectList>
</Select>
)} )}
/> />
</UserProfileGroup> </UserProfileGroup>