fetch and save client (#116)
* fetch and save client * added multi line for redirect uris * format * review
This commit is contained in:
parent
19b458577b
commit
94b26936d3
8 changed files with 148 additions and 103 deletions
|
@ -38,7 +38,7 @@ export const App = () => {
|
|||
<Route exact path="/clients" component={ClientsSection}></Route>
|
||||
<Route
|
||||
exact
|
||||
path="/client-settings"
|
||||
path="/client-settings/:id"
|
||||
component={ClientSettings}
|
||||
></Route>
|
||||
<Route exact path="/add-client" component={NewClientForm}></Route>
|
||||
|
|
|
@ -36,16 +36,13 @@ export const ClientList = ({ baseUrl, clients }: ClientListProps) => {
|
|||
const { realm } = useContext(RealmContext);
|
||||
const [add, Alerts] = useAlerts();
|
||||
|
||||
const convertClientId = (clientId: string) =>
|
||||
clientId.substring(0, clientId.indexOf("#"));
|
||||
const enabled = (): IFormatter => (data?: IFormatterValueType) => {
|
||||
const field = data!.toString();
|
||||
const value = convertClientId(field);
|
||||
return field.indexOf("true") !== -1 ? (
|
||||
<Link to="client-settings">{value}</Link>
|
||||
) : (
|
||||
<Link to="client-settings">
|
||||
{value} <Badge isRead>Disabled</Badge>
|
||||
const [id, clientId, disabled] = field.split("#");
|
||||
return (
|
||||
<Link to={`client-settings/${id}`}>
|
||||
{clientId}
|
||||
{disabled !== "true" && <Badge isRead>Disabled</Badge>}
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
@ -75,13 +72,13 @@ export const ClientList = ({ baseUrl, clients }: ClientListProps) => {
|
|||
};
|
||||
|
||||
const data = clients!
|
||||
.map((r) => {
|
||||
r.clientId = r.clientId + "#" + r.enabled;
|
||||
r.baseUrl = replaceBaseUrl(r);
|
||||
return r;
|
||||
.map((client) => {
|
||||
client.clientId = `${client.id}#${client.clientId}#${client.enabled}`;
|
||||
client.baseUrl = replaceBaseUrl(client);
|
||||
return client;
|
||||
})
|
||||
.map((c) => {
|
||||
return { cells: columns.map((col) => c[col]), client: c };
|
||||
.map((column) => {
|
||||
return { cells: columns.map((col) => column[col]), client: column };
|
||||
});
|
||||
return (
|
||||
<>
|
||||
|
@ -103,7 +100,8 @@ export const ClientList = ({ baseUrl, clients }: ClientListProps) => {
|
|||
title: t("common:export"),
|
||||
onClick: (_, rowId) => {
|
||||
const clientCopy = JSON.parse(JSON.stringify(data[rowId].client));
|
||||
clientCopy.clientId = convertClientId(clientCopy.clientId);
|
||||
const [, orgClientId] = clientCopy.clientId.split("#");
|
||||
clientCopy.clientId = orgClientId;
|
||||
delete clientCopy.id;
|
||||
|
||||
if (clientCopy.protocolMappers) {
|
||||
|
|
|
@ -1,45 +1,72 @@
|
|||
import React, { useState, FormEvent } from "react";
|
||||
import React, { useContext, useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import {
|
||||
FormGroup,
|
||||
TextInput,
|
||||
Form,
|
||||
Dropdown,
|
||||
DropdownToggle,
|
||||
DropdownItem,
|
||||
Switch,
|
||||
TextArea,
|
||||
PageSection,
|
||||
ActionGroup,
|
||||
Button,
|
||||
AlertVariant,
|
||||
} from "@patternfly/react-core";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
|
||||
import { ScrollForm } from "../components/scroll-form/ScrollForm";
|
||||
import { ClientDescription } from "./ClientDescription";
|
||||
import { ClientRepresentation } from "./models/client-model";
|
||||
import { CapabilityConfig } from "./add/CapabilityConfig";
|
||||
import { RealmContext } from "../components/realm-context/RealmContext";
|
||||
import { HttpClientContext } from "../http-service/HttpClientContext";
|
||||
import { ClientRepresentation } from "../realm/models/Realm";
|
||||
import {
|
||||
convertToMultiline,
|
||||
MultiLineInput,
|
||||
toValue,
|
||||
} from "../components/multi-line-input/MultiLineInput";
|
||||
import { useAlerts } from "../components/alert/Alerts";
|
||||
|
||||
type ClientSettingsProps = {
|
||||
client: ClientRepresentation;
|
||||
};
|
||||
|
||||
export const ClientSettings = ({ client: clientInit }: ClientSettingsProps) => {
|
||||
export const ClientSettings = () => {
|
||||
const { t } = useTranslation("clients");
|
||||
const [client, setClient] = useState({ ...clientInit });
|
||||
const form = useForm();
|
||||
const onChange = (
|
||||
value: string | boolean,
|
||||
event: FormEvent<HTMLInputElement>
|
||||
) => {
|
||||
const target = event.target;
|
||||
const name = (target as HTMLInputElement).name;
|
||||
const httpClient = useContext(HttpClientContext)!;
|
||||
const { realm } = useContext(RealmContext);
|
||||
const [addAlert, Alerts] = useAlerts();
|
||||
|
||||
setClient({
|
||||
...client,
|
||||
[name]: value,
|
||||
const { id } = useParams<{ id: string }>();
|
||||
const form = useForm();
|
||||
const url = `/admin/realms/${realm}/clients/${id}`;
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
const fetchedClient = await httpClient.doGet<ClientRepresentation>(url);
|
||||
if (fetchedClient.data) {
|
||||
Object.entries(fetchedClient.data).map((entry) => {
|
||||
if (entry[0] !== "redirectUris") {
|
||||
form.setValue(entry[0], entry[1]);
|
||||
} else if (entry[1] && entry[1].length > 0) {
|
||||
form.setValue(entry[0], convertToMultiline(entry[1]));
|
||||
}
|
||||
});
|
||||
}
|
||||
})();
|
||||
}, []);
|
||||
|
||||
const save = async () => {
|
||||
if (await form.trigger()) {
|
||||
const redirectUris = toValue(form.getValues()["redirectUris"]);
|
||||
try {
|
||||
httpClient.doPut(url, { ...form.getValues(), redirectUris });
|
||||
addAlert(t("clientSaveSuccess"), AlertVariant.success);
|
||||
} catch (error) {
|
||||
addAlert(`${t("clientSaveError")} '${error}'`, AlertVariant.danger);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<PageSection>
|
||||
<Alerts />
|
||||
<ScrollForm
|
||||
sections={[
|
||||
t("capabilityConfig"),
|
||||
|
@ -48,9 +75,7 @@ export const ClientSettings = ({ client: clientInit }: ClientSettingsProps) => {
|
|||
t("loginSettings"),
|
||||
]}
|
||||
>
|
||||
<Form isHorizontal>
|
||||
<CapabilityConfig form={form} />
|
||||
</Form>
|
||||
<Form isHorizontal>
|
||||
<ClientDescription form={form} />
|
||||
</Form>
|
||||
|
@ -60,65 +85,56 @@ export const ClientSettings = ({ client: clientInit }: ClientSettingsProps) => {
|
|||
type="text"
|
||||
id="kc-root-url"
|
||||
name="rootUrl"
|
||||
value={client.rootUrl}
|
||||
onChange={onChange}
|
||||
ref={form.register}
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup label={t("validRedirectUri")} fieldId="kc-redirect">
|
||||
<TextInput
|
||||
type="text"
|
||||
id="kc-redirect"
|
||||
name="redirectUris"
|
||||
onChange={onChange}
|
||||
/>
|
||||
<MultiLineInput form={form} name="redirectUris" />
|
||||
</FormGroup>
|
||||
<FormGroup label={t("homeURL")} fieldId="kc-home-url">
|
||||
<TextInput
|
||||
type="text"
|
||||
id="kc-home-url"
|
||||
name="baseUrl"
|
||||
value={client.baseUrl}
|
||||
onChange={onChange}
|
||||
ref={form.register}
|
||||
/>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
<Form isHorizontal>
|
||||
<FormGroup label={t("loginTheme")} fieldId="kc-login-theme">
|
||||
<Dropdown
|
||||
id="kc-login-theme"
|
||||
toggle={
|
||||
<DropdownToggle id="toggle-id" onToggle={() => {}}>
|
||||
{t("loginTheme")}
|
||||
</DropdownToggle>
|
||||
}
|
||||
dropdownItems={[
|
||||
<DropdownItem key="link">Link</DropdownItem>,
|
||||
<DropdownItem key="action" component="button" />,
|
||||
]}
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup label={t("consentRequired")} fieldId="kc-consent">
|
||||
<Controller
|
||||
name="consentRequired"
|
||||
defaultValue={false}
|
||||
control={form.control}
|
||||
render={({ onChange, value }) => (
|
||||
<Switch
|
||||
id="kc-consent"
|
||||
name="consentRequired"
|
||||
label={t("common:on")}
|
||||
labelOff={t("common:off")}
|
||||
isChecked={client.consentRequired}
|
||||
isChecked={value}
|
||||
onChange={onChange}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup
|
||||
label={t("displayOnClient")}
|
||||
fieldId="kc-display-on-client"
|
||||
>
|
||||
<Controller
|
||||
name="alwaysDisplayInConsole"
|
||||
defaultValue={false}
|
||||
control={form.control}
|
||||
render={({ onChange, value }) => (
|
||||
<Switch
|
||||
id="kc-display-on-client"
|
||||
name="alwaysDisplayInConsole"
|
||||
label={t("common:on")}
|
||||
labelOff={t("common:off")}
|
||||
isChecked={client.alwaysDisplayInConsole}
|
||||
isChecked={value}
|
||||
onChange={onChange}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup
|
||||
label={t("consentScreenText")}
|
||||
|
@ -127,9 +143,15 @@ export const ClientSettings = ({ client: clientInit }: ClientSettingsProps) => {
|
|||
<TextArea
|
||||
id="kc-consent-screen-text"
|
||||
name="consentText"
|
||||
//value={client.protocolMappers![0].consentText}
|
||||
ref={form.register}
|
||||
/>
|
||||
</FormGroup>
|
||||
<ActionGroup>
|
||||
<Button variant="primary" onClick={() => save()}>
|
||||
{t("common:save")}
|
||||
</Button>
|
||||
<Button variant="link">{t("common:cancel")}</Button>
|
||||
</ActionGroup>
|
||||
</Form>
|
||||
</ScrollForm>
|
||||
</PageSection>
|
||||
|
|
|
@ -71,7 +71,7 @@ Object {
|
|||
data-label="clientID"
|
||||
>
|
||||
<a
|
||||
href="/client-settings"
|
||||
href="/client-settings/767756c2-21f8-431c-9f4b-edf30654d653"
|
||||
>
|
||||
account
|
||||
</a>
|
||||
|
@ -170,7 +170,7 @@ Object {
|
|||
data-label="clientID"
|
||||
>
|
||||
<a
|
||||
href="/client-settings"
|
||||
href="/client-settings/337dc87b-e08d-409e-aaac-6ab7df4b925b"
|
||||
>
|
||||
account-console
|
||||
</a>
|
||||
|
@ -269,7 +269,7 @@ Object {
|
|||
data-label="clientID"
|
||||
>
|
||||
<a
|
||||
href="/client-settings"
|
||||
href="/client-settings/60d59afe-7926-4c22-b829-798125793ef5"
|
||||
>
|
||||
admin-cli
|
||||
</a>
|
||||
|
@ -342,7 +342,7 @@ Object {
|
|||
data-label="clientID"
|
||||
>
|
||||
<a
|
||||
href="/client-settings"
|
||||
href="/client-settings/c2d74093-2b8c-4ecb-870f-c7358ff48237"
|
||||
>
|
||||
broker
|
||||
</a>
|
||||
|
@ -415,7 +415,7 @@ Object {
|
|||
data-label="clientID"
|
||||
>
|
||||
<a
|
||||
href="/client-settings"
|
||||
href="/client-settings/66135023-e667-4864-b1f3-f87e805fabc2"
|
||||
>
|
||||
master-realm
|
||||
</a>
|
||||
|
@ -486,7 +486,7 @@ Object {
|
|||
data-label="clientID"
|
||||
>
|
||||
<a
|
||||
href="/client-settings"
|
||||
href="/client-settings/324f4182-d302-44f8-ac8a-149eaa29dc90"
|
||||
>
|
||||
new
|
||||
</a>
|
||||
|
@ -585,7 +585,7 @@ Object {
|
|||
data-label="clientID"
|
||||
>
|
||||
<a
|
||||
href="/client-settings"
|
||||
href="/client-settings/fb45882b-4d85-4f40-920e-6a68298d36d0"
|
||||
>
|
||||
photoz-realm
|
||||
</a>
|
||||
|
@ -656,7 +656,7 @@ Object {
|
|||
data-label="clientID"
|
||||
>
|
||||
<a
|
||||
href="/client-settings"
|
||||
href="/client-settings/9ed60e41-d794-4046-842f-3247bf32f5ce"
|
||||
>
|
||||
security-admin-console
|
||||
</a>
|
||||
|
@ -819,7 +819,7 @@ Object {
|
|||
data-label="clientID"
|
||||
>
|
||||
<a
|
||||
href="/client-settings"
|
||||
href="/client-settings/767756c2-21f8-431c-9f4b-edf30654d653"
|
||||
>
|
||||
account
|
||||
</a>
|
||||
|
@ -918,7 +918,7 @@ Object {
|
|||
data-label="clientID"
|
||||
>
|
||||
<a
|
||||
href="/client-settings"
|
||||
href="/client-settings/337dc87b-e08d-409e-aaac-6ab7df4b925b"
|
||||
>
|
||||
account-console
|
||||
</a>
|
||||
|
@ -1017,7 +1017,7 @@ Object {
|
|||
data-label="clientID"
|
||||
>
|
||||
<a
|
||||
href="/client-settings"
|
||||
href="/client-settings/60d59afe-7926-4c22-b829-798125793ef5"
|
||||
>
|
||||
admin-cli
|
||||
</a>
|
||||
|
@ -1090,7 +1090,7 @@ Object {
|
|||
data-label="clientID"
|
||||
>
|
||||
<a
|
||||
href="/client-settings"
|
||||
href="/client-settings/c2d74093-2b8c-4ecb-870f-c7358ff48237"
|
||||
>
|
||||
broker
|
||||
</a>
|
||||
|
@ -1163,7 +1163,7 @@ Object {
|
|||
data-label="clientID"
|
||||
>
|
||||
<a
|
||||
href="/client-settings"
|
||||
href="/client-settings/66135023-e667-4864-b1f3-f87e805fabc2"
|
||||
>
|
||||
master-realm
|
||||
</a>
|
||||
|
@ -1234,7 +1234,7 @@ Object {
|
|||
data-label="clientID"
|
||||
>
|
||||
<a
|
||||
href="/client-settings"
|
||||
href="/client-settings/324f4182-d302-44f8-ac8a-149eaa29dc90"
|
||||
>
|
||||
new
|
||||
</a>
|
||||
|
@ -1333,7 +1333,7 @@ Object {
|
|||
data-label="clientID"
|
||||
>
|
||||
<a
|
||||
href="/client-settings"
|
||||
href="/client-settings/fb45882b-4d85-4f40-920e-6a68298d36d0"
|
||||
>
|
||||
photoz-realm
|
||||
</a>
|
||||
|
@ -1404,7 +1404,7 @@ Object {
|
|||
data-label="clientID"
|
||||
>
|
||||
<a
|
||||
href="/client-settings"
|
||||
href="/client-settings/9ed60e41-d794-4046-842f-3247bf32f5ce"
|
||||
>
|
||||
security-admin-console
|
||||
</a>
|
||||
|
|
|
@ -21,6 +21,7 @@ export const CapabilityConfig = ({ form }: CapabilityConfigProps) => {
|
|||
<FormGroup label={t("clientAuthentication")} fieldId="kc-authentication">
|
||||
<Controller
|
||||
name="publicClient"
|
||||
defaultValue={false}
|
||||
control={form.control}
|
||||
render={({ onChange, value }) => (
|
||||
<Switch
|
||||
|
@ -37,6 +38,7 @@ export const CapabilityConfig = ({ form }: CapabilityConfigProps) => {
|
|||
<FormGroup label={t("clientAuthorization")} fieldId="kc-authorization">
|
||||
<Controller
|
||||
name="authorizationServicesEnabled"
|
||||
defaultValue={false}
|
||||
control={form.control}
|
||||
render={({ onChange, value }) => (
|
||||
<Switch
|
||||
|
@ -55,6 +57,7 @@ export const CapabilityConfig = ({ form }: CapabilityConfigProps) => {
|
|||
<GridItem lg={4} sm={6}>
|
||||
<Controller
|
||||
name="standardFlowEnabled"
|
||||
defaultValue={false}
|
||||
control={form.control}
|
||||
render={({ onChange, value }) => (
|
||||
<Checkbox
|
||||
|
@ -70,6 +73,7 @@ export const CapabilityConfig = ({ form }: CapabilityConfigProps) => {
|
|||
<GridItem lg={8} sm={6}>
|
||||
<Controller
|
||||
name="directAccessGrantsEnabled"
|
||||
defaultValue={false}
|
||||
control={form.control}
|
||||
render={({ onChange, value }) => (
|
||||
<Checkbox
|
||||
|
@ -85,6 +89,7 @@ export const CapabilityConfig = ({ form }: CapabilityConfigProps) => {
|
|||
<GridItem lg={4} sm={6}>
|
||||
<Controller
|
||||
name="implicitFlowEnabled"
|
||||
defaultValue={false}
|
||||
control={form.control}
|
||||
render={({ onChange, value }) => (
|
||||
<Checkbox
|
||||
|
@ -100,6 +105,7 @@ export const CapabilityConfig = ({ form }: CapabilityConfigProps) => {
|
|||
<GridItem lg={8} sm={6}>
|
||||
<Controller
|
||||
name="serviceAccountsEnabled"
|
||||
defaultValue={false}
|
||||
control={form.control}
|
||||
render={({ onChange, value }) => (
|
||||
<Checkbox
|
||||
|
|
|
@ -14,7 +14,9 @@
|
|||
"capabilityConfig": "Capability config",
|
||||
"clientsExplain": "Clients are applications and services that can request authentication of a user",
|
||||
"clientImportError": "Could not import client",
|
||||
"clientImportSuccess": "Client imported successful",
|
||||
"clientSaveSuccess": "Client successfully updated",
|
||||
"clientSaveError": "Client could not be updated:",
|
||||
"clientImportSuccess": "Client imported successfully",
|
||||
"clientDeletedSuccess": "The client has been deleted",
|
||||
"clientDeleteError": "Could not delete client:",
|
||||
"clientAuthentication": "Client authentication",
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import React from "react";
|
||||
import React, { useEffect } from "react";
|
||||
import { useFieldArray, UseFormMethods } from "react-hook-form";
|
||||
import {
|
||||
TextInput,
|
||||
|
@ -9,6 +9,20 @@ import {
|
|||
} from "@patternfly/react-core";
|
||||
import { MinusIcon, PlusIcon } from "@patternfly/react-icons";
|
||||
|
||||
type MultiLine = {
|
||||
value: string;
|
||||
};
|
||||
|
||||
export function convertToMultiline(fields: string[]): MultiLine[] {
|
||||
return fields.map((field) => {
|
||||
return { value: field };
|
||||
});
|
||||
}
|
||||
|
||||
export function toValue(formValue: MultiLine[]): string[] {
|
||||
return formValue.map((field) => field.value);
|
||||
}
|
||||
|
||||
export type MultiLineInputProps = {
|
||||
form: UseFormMethods;
|
||||
name: string;
|
||||
|
@ -20,12 +34,18 @@ export const MultiLineInput = ({ name, form }: MultiLineInputProps) => {
|
|||
name,
|
||||
control,
|
||||
});
|
||||
useEffect(() => {
|
||||
form.reset({
|
||||
[name]: [{ value: "" }],
|
||||
});
|
||||
}, []);
|
||||
return (
|
||||
<>
|
||||
{fields.map(({ id, value }, index) => (
|
||||
<Split key={id}>
|
||||
<SplitItem>
|
||||
<TextInput
|
||||
id={id}
|
||||
ref={register()}
|
||||
name={`${name}[${index}].value`}
|
||||
defaultValue={value}
|
||||
|
|
|
@ -7,6 +7,7 @@ import { Button } from "@patternfly/react-core";
|
|||
import {
|
||||
MultiLineInput,
|
||||
MultiLineInputProps,
|
||||
toValue,
|
||||
} from "../components/multi-line-input/MultiLineInput";
|
||||
|
||||
export default {
|
||||
|
@ -15,15 +16,11 @@ export default {
|
|||
} as Meta;
|
||||
|
||||
const Template: Story<MultiLineInputProps> = (args) => {
|
||||
const form = useForm({
|
||||
defaultValues: {
|
||||
items: [{ value: "" }],
|
||||
},
|
||||
});
|
||||
const form = useForm();
|
||||
return (
|
||||
<form
|
||||
onSubmit={form.handleSubmit((data) => {
|
||||
action("submit")(data);
|
||||
action("submit")(toValue(data.items));
|
||||
})}
|
||||
>
|
||||
<MultiLineInput {...args} form={form} />
|
||||
|
|
Loading…
Reference in a new issue