Use user select component (#4011)

This commit is contained in:
Erik Jan de Wit 2022-12-13 06:40:49 -05:00 committed by GitHub
parent 91acceacd0
commit be59ed1447
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 32 additions and 78 deletions

View file

@ -1,3 +1,7 @@
import type ClientScopeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientScopeRepresentation";
import type ProtocolMapperRepresentation from "@keycloak/keycloak-admin-client/lib/defs/protocolMapperRepresentation";
import type RoleRepresentation from "@keycloak/keycloak-admin-client/lib/defs/roleRepresentation";
import type { ProtocolMapperTypeRepresentation } from "@keycloak/keycloak-admin-client/lib/defs/serverInfoRepesentation";
import {
ClipboardCopy,
Form,
@ -18,16 +22,14 @@ import {
TextContent,
} from "@patternfly/react-core";
import { QuestionCircleIcon } from "@patternfly/react-icons";
import type ClientScopeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientScopeRepresentation";
import type ProtocolMapperRepresentation from "@keycloak/keycloak-admin-client/lib/defs/protocolMapperRepresentation";
import type RoleRepresentation from "@keycloak/keycloak-admin-client/lib/defs/roleRepresentation";
import type { ProtocolMapperTypeRepresentation } from "@keycloak/keycloak-admin-client/lib/defs/serverInfoRepesentation";
import type UserRepresentation from "@keycloak/keycloak-admin-client/lib/defs/userRepresentation";
import { useEffect, useRef, useState } from "react";
import { FormProvider, useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { useHelp } from "../../components/help-enabler/HelpHeader";
import { HelpItem } from "../../components/help-enabler/HelpItem";
import { KeycloakDataTable } from "../../components/table-toolbar/KeycloakDataTable";
import { UserSelect } from "../../components/users/UserSelect";
import { useAdminClient, useFetch } from "../../context/auth/AdminClient";
import { useRealm } from "../../context/realm-context/RealmContext";
import { useServerInfo } from "../../context/server-info/ServerInfoProvider";
@ -120,14 +122,9 @@ export const EvaluateScopes = ({ clientId, protocol }: EvaluateScopesProps) => {
ClientScopeRepresentation[]
>([]);
const [isScopeOpen, setIsScopeOpen] = useState(false);
const [isUserOpen, setIsUserOpen] = useState(false);
const [selected, setSelected] = useState<string[]>([prefix]);
const [activeTab, setActiveTab] = useState(0);
const [userItems, setUserItems] = useState<JSX.Element[]>([]);
const [userSearch, setUserSearch] = useState("");
const [user, setUser] = useState<UserRepresentation>();
const [key, setKey] = useState("");
const refresh = () => setKey(`${new Date().getTime()}`);
const [effectiveRoles, setEffectiveRoles] = useState<RoleRepresentation[]>(
@ -146,39 +143,14 @@ export const EvaluateScopes = ({ clientId, protocol }: EvaluateScopesProps) => {
const tabContent4 = useRef(null);
const tabContent5 = useRef(null);
const form = useForm();
useFetch(
() => adminClient.clients.listOptionalClientScopes({ id: clientId }),
(optionalClientScopes) => setSelectableScopes(optionalClientScopes),
[]
);
const toString = (user: UserRepresentation) => {
return (
t("common:fullName", {
givenName: user.firstName,
familyName: user.lastName,
}).trim() ||
user.username ||
""
);
};
useFetch(
() => adminClient.users.find({ search: userSearch }),
(users) =>
setUserItems(
users
.map((user) => {
user.toString = function () {
return toString(this);
};
return user;
})
.map((user) => <SelectOption key={user.id} value={user} />)
),
[userSearch]
);
useFetch(
async () => {
const scope = selected.join(" ");
@ -218,22 +190,23 @@ export const EvaluateScopes = ({ clientId, protocol }: EvaluateScopesProps) => {
useFetch(
async () => {
const scope = selected.join(" ");
const user = form.getValues("user");
if (!user) return [];
return await Promise.all([
adminClient.clients.evaluateGenerateAccessToken({
id: clientId,
userId: user.id!,
userId: user[0],
scope,
}),
adminClient.clients.evaluateGenerateUserInfo({
id: clientId,
userId: user.id!,
userId: user[0],
scope,
}),
adminClient.clients.evaluateGenerateIdToken({
id: clientId,
userId: user.id!,
userId: user[0],
scope,
}),
]);
@ -243,7 +216,7 @@ export const EvaluateScopes = ({ clientId, protocol }: EvaluateScopesProps) => {
setUserInfo(prettyPrintJSON(userInfo));
setIdToken(prettyPrintJSON(idToken));
},
[user, selected]
[form.getValues("user"), selected]
);
return (
@ -301,39 +274,16 @@ export const EvaluateScopes = ({ clientId, protocol }: EvaluateScopesProps) => {
</SplitItem>
</Split>
</FormGroup>
<FormGroup
label={t("user")}
fieldId="user"
labelIcon={
<HelpItem
<FormProvider {...form}>
<UserSelect
name="user"
label="users"
helpText="clients-help:user"
fieldLabelId="clients:user"
/>
}
>
<Select
toggleId="user"
defaultValue=""
variant={SelectVariant.typeahead}
typeAheadAriaLabel={t("user")}
onToggle={() => setIsUserOpen(!isUserOpen)}
onFilter={(e) => {
const value = e?.target.value || "";
setUserSearch(value);
return userItems;
}}
onClear={() => {
setUser(undefined);
setUserSearch("");
}}
selections={[user]}
onSelect={(_, value) => {
setUser(value as UserRepresentation);
setUserSearch("");
setIsUserOpen(false);
}}
isOpen={isUserOpen}
isRequired
/>
</FormGroup>
</FormProvider>
</Form>
</PageSection>
@ -365,7 +315,7 @@ export const EvaluateScopes = ({ clientId, protocol }: EvaluateScopesProps) => {
>
<GeneratedCodeTab
text={accessToken}
user={user}
user={form.getValues("user")}
label="generatedAccessToken"
/>
</TabContent>
@ -378,7 +328,7 @@ export const EvaluateScopes = ({ clientId, protocol }: EvaluateScopesProps) => {
>
<GeneratedCodeTab
text={idToken}
user={user}
user={form.getValues("user")}
label="generatedIdToken"
/>
</TabContent>
@ -391,7 +341,7 @@ export const EvaluateScopes = ({ clientId, protocol }: EvaluateScopesProps) => {
>
<GeneratedCodeTab
text={userInfo}
user={user}
user={form.getValues("user")}
label="generatedUserInfo"
/>
</TabContent>

View file

@ -1,4 +1,4 @@
import { useState } from "react";
import { useCallback, useState } from "react";
import { useTranslation } from "react-i18next";
import { Controller, useFormContext } from "react-hook-form";
import {
@ -7,6 +7,7 @@ import {
Select,
SelectVariant,
} from "@patternfly/react-core";
import { debounce } from "lodash-es";
import type UserRepresentation from "@keycloak/keycloak-admin-client/lib/defs/userRepresentation";
import type { UserQuery } from "@keycloak/keycloak-admin-client/lib/resources/users";
@ -42,6 +43,7 @@ export const UserSelect = ({
const [search, setSearch] = useState("");
const { adminClient } = useAdminClient();
const debounceFn = useCallback(debounce(setSearch, 1000), []);
useFetch(
() => {
@ -107,12 +109,14 @@ export const UserSelect = ({
isOpen={open}
selections={value}
onFilter={(_, value) => {
setSearch(value);
debounceFn(value);
return convert(users);
}}
onSelect={(_, v) => {
const option = v.toString();
if (value.includes(option)) {
if (variant !== SelectVariant.typeaheadMulti) {
onChange([option]);
} else if (value.includes(option)) {
onChange(value.filter((item: string) => item !== option));
} else {
onChange([...value, option]);