Realm settings(localization): Add bundle functionality (#739)
* wip provider details provider details wip move files wip wip wip all provider details remove controllers save and update working address console warnings remove log stmt update test keep aes only remove comments remove unused hook and function remove unused props revert ldap logs fix conflict and remove duplicate function Partial import phase 2 (#702) * Process the JSON and present user options * Finish checkboxes. Refactor. * Add tests * Refactor after rebase * Add more test data for manual testing. * Fix linting errors * Put JsonFileUpload back the way it was. * Clean up comments * Update src/realm-settings/PartialImport.tsx Remove comment Co-authored-by: Jenny <32821331+jenny-s51@users.noreply.github.com> Co-authored-by: Jenny <32821331+jenny-s51@users.noreply.github.com> Fixing UXD review for user (#648) * Introduced new GroupPicker. Can be used for move group or join group * Moved help texts to help.json * don't set state when there was no request * add pagination * remove "Groups" link on root level * use path in chip instread of name * fixes filtering to show search not found and removes `+1` logic from pager * fix breadcrumb and layout * fixed all the tests Localization tab (#685) * localization wip wip localization return key value data as array localization table css lint lint clean up log stmts clean up log stmts * PR feedback from Erik * fix logic for supported locales * update empty state text * set default value * fix cypress test * Update src/realm-settings/RealmSettingsSection.tsx Co-authored-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * fix rsa-generated delete bug; PR feedback frog Erik * revert locale abbreviation * remove log stmts * PR feedback from Erik, fix undefined * fix loader w Erik Co-authored-by: Erik Jan de Wit <erikjan.dewit@gmail.com> add divider on section Prepare for first alpha release (#711) use typeahead for mapper list fix test Default roles: UI Changes from KEYCLOAK-14846 (#693) * defaultRoles wip default role changes done clean up log stmts update snapshot fix masthead test * fix cypress test * fix tabs Comment out Realm role CRUD test (#712) * Bogus change * Bogus change * Comment out Realm role CRUD test Bump postcss-cli from 7.1.1 to 8.3.1 (#718) Bumps [postcss-cli](https://github.com/postcss/postcss-cli) from 7.1.1 to 8.3.1. - [Release notes](https://github.com/postcss/postcss-cli/releases) - [Changelog](https://github.com/postcss/postcss-cli/blob/master/CHANGELOG.md) - [Commits](https://github.com/postcss/postcss-cli/compare/7.1.1...8.3.1) --- updated-dependencies: - dependency-name: postcss-cli dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Bump @testing-library/jest-dom from 5.12.0 to 5.14.1 (#717) Bumps [@testing-library/jest-dom](https://github.com/testing-library/jest-dom) from 5.12.0 to 5.14.1. - [Release notes](https://github.com/testing-library/jest-dom/releases) - [Changelog](https://github.com/testing-library/jest-dom/blob/main/CHANGELOG.md) - [Commits](https://github.com/testing-library/jest-dom/compare/v5.12.0...v5.14.1) --- updated-dependencies: - dependency-name: "@testing-library/jest-dom" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> fixing issue (#709) * fixing issue fixing: #680 * added kebab on row * added more clear group seperation Bump cypress from 7.4.0 to 7.5.0 (#715) Bump @babel/preset-typescript from 7.13.0 to 7.14.5 (#714) Bumps [@babel/preset-typescript](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-typescript) from 7.13.0 to 7.14.5. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.14.5/packages/babel-preset-typescript) --- updated-dependencies: - dependency-name: "@babel/preset-typescript" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Bump @testing-library/react from 10.4.6 to 11.2.7 (#716) Bumps [@testing-library/react](https://github.com/testing-library/react-testing-library) from 10.4.6 to 11.2.7. - [Release notes](https://github.com/testing-library/react-testing-library/releases) - [Changelog](https://github.com/testing-library/react-testing-library/blob/main/CHANGELOG.md) - [Commits](https://github.com/testing-library/react-testing-library/compare/v10.4.6...v11.2.7) --- updated-dependencies: - dependency-name: "@testing-library/react" dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> inherited roles disabled instead of non selectable more style fixes fixed size change title of tab add unassign kebab on row added help item on enable switch test email working, modal wip email connection done remove comment fix cypress test revert test file fdisable email prompting when user email entered prettier update cypress tests fix lint try fix cypress test try longer wait save and test connection make wait longer increase wait fix test disable test connection button if form fields not entered lint afix username/password fields fix test mark suggested change add modal button and input functions fixed default value warning fixing issue fixing: #650 updated admin client with new endpoints (#725) fix add function and add test remove aes provider changes remove comments format update cypress test update add bundle function fix test remove comment * remove merge conflict markers * more markers * format
This commit is contained in:
parent
1613331bba
commit
d53542f3df
7 changed files with 254 additions and 14 deletions
|
@ -40,6 +40,19 @@ describe("Realm settings", () => {
|
|||
return this;
|
||||
};
|
||||
|
||||
const addBundle = () => {
|
||||
const localizationUrl =
|
||||
"/auth/admin/realms/master/realm-settings/localization";
|
||||
cy.intercept(localizationUrl).as("localizationFetch");
|
||||
|
||||
realmSettingsPage.addKeyValuePair(
|
||||
"key_" + (Math.random() + 1).toString(36).substring(7),
|
||||
"value_" + (Math.random() + 1).toString(36).substring(7)
|
||||
);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
it("Go to general tab", function () {
|
||||
sidebarPage.goToRealmSettings();
|
||||
realmSettingsPage.toggleSwitch(realmSettingsPage.managedAccessSwitch);
|
||||
|
@ -142,13 +155,10 @@ describe("Realm settings", () => {
|
|||
});
|
||||
|
||||
it("add Providers", () => {
|
||||
cy.wait(5000);
|
||||
sidebarPage.goToRealmSettings();
|
||||
|
||||
cy.getId("rs-keys-tab").click();
|
||||
|
||||
cy.wait(10000);
|
||||
|
||||
cy.getId("rs-providers-tab").click();
|
||||
|
||||
realmSettingsPage.toggleAddProviderDropdown();
|
||||
|
@ -182,4 +192,16 @@ describe("Realm settings", () => {
|
|||
|
||||
realmSettingsPage.testSelectFilter();
|
||||
});
|
||||
|
||||
it("add locale", () => {
|
||||
sidebarPage.goToRealmSettings();
|
||||
|
||||
cy.getId("rs-localization-tab").click();
|
||||
|
||||
addBundle();
|
||||
|
||||
masthead.checkNotificationMessage(
|
||||
"Success! The localization text has been created."
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -39,6 +39,10 @@ export default class RealmSettingsPage {
|
|||
testConnectionButton = "test-connection-button";
|
||||
modalTestConnectionButton = "modal-test-connection-button";
|
||||
emailAddressInput = "email-address-input";
|
||||
addBundleButton = "no-message-bundles-empty-action";
|
||||
confirmAddBundle = "add-bundle-confirm-button";
|
||||
keyInput = "key-input";
|
||||
valueInput = "value-input";
|
||||
|
||||
selectLoginThemeType(themeType: string) {
|
||||
const themesUrl = "/auth/admin/realms/master/themes";
|
||||
|
@ -139,6 +143,17 @@ export default class RealmSettingsPage {
|
|||
return this;
|
||||
}
|
||||
|
||||
addKeyValuePair(key: string, value: string) {
|
||||
cy.getId(this.addBundleButton).click();
|
||||
|
||||
cy.getId(this.keyInput).type(key);
|
||||
cy.getId(this.valueInput).type(value);
|
||||
|
||||
cy.getId(this.confirmAddBundle).click();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
enterConsoleDisplayName(name: string) {
|
||||
cy.getId(this.displayName).clear().type(name);
|
||||
}
|
||||
|
|
111
src/realm-settings/AddMessageBundleModal.tsx
Normal file
111
src/realm-settings/AddMessageBundleModal.tsx
Normal file
|
@ -0,0 +1,111 @@
|
|||
import React from "react";
|
||||
import {
|
||||
Button,
|
||||
ButtonVariant,
|
||||
Form,
|
||||
FormGroup,
|
||||
Modal,
|
||||
ModalVariant,
|
||||
TextInput,
|
||||
ValidatedOptions,
|
||||
} from "@patternfly/react-core";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useForm, UseFormMethods } from "react-hook-form";
|
||||
|
||||
type AddMessageBundleModalProps = {
|
||||
id?: string;
|
||||
form: UseFormMethods<BundleForm>;
|
||||
save: (model: BundleForm) => void;
|
||||
handleModalToggle: () => void;
|
||||
};
|
||||
|
||||
export type KeyValueType = { key: string; value: string };
|
||||
|
||||
export type BundleForm = {
|
||||
messageBundle: KeyValueType;
|
||||
};
|
||||
|
||||
export const AddMessageBundleModal = ({
|
||||
handleModalToggle,
|
||||
save,
|
||||
}: AddMessageBundleModalProps) => {
|
||||
const { t } = useTranslation("groups");
|
||||
const { register, errors, handleSubmit } = useForm();
|
||||
|
||||
return (
|
||||
<Modal
|
||||
variant={ModalVariant.small}
|
||||
title={t("realm-settings:addMessageBundle")}
|
||||
isOpen={true}
|
||||
onClose={handleModalToggle}
|
||||
actions={[
|
||||
<Button
|
||||
data-testid="add-bundle-confirm-button"
|
||||
key="confirm"
|
||||
variant="primary"
|
||||
type="submit"
|
||||
form="bundle-form"
|
||||
>
|
||||
{t("common:create")}
|
||||
</Button>,
|
||||
<Button
|
||||
id="modal-cancel"
|
||||
key="cancel"
|
||||
variant={ButtonVariant.link}
|
||||
onClick={() => {
|
||||
handleModalToggle();
|
||||
}}
|
||||
>
|
||||
{t("common:cancel")}
|
||||
</Button>,
|
||||
]}
|
||||
>
|
||||
<Form id="bundle-form" isHorizontal onSubmit={handleSubmit(save)}>
|
||||
<FormGroup
|
||||
label={t("realm-settings:key")}
|
||||
name="key"
|
||||
fieldId="email-id"
|
||||
helperTextInvalid={t("users:emailInvalid")}
|
||||
validated={
|
||||
errors.email ? ValidatedOptions.error : ValidatedOptions.default
|
||||
}
|
||||
isRequired
|
||||
>
|
||||
<TextInput
|
||||
data-testid="key-input"
|
||||
ref={register({ required: true })}
|
||||
autoFocus
|
||||
type="text"
|
||||
id="add-key"
|
||||
name="key"
|
||||
validated={
|
||||
errors.email ? ValidatedOptions.error : ValidatedOptions.default
|
||||
}
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup
|
||||
label={t("realm-settings:value")}
|
||||
name="add-value"
|
||||
fieldId="value-id"
|
||||
helperTextInvalid={t("users:emailInvalid")}
|
||||
validated={
|
||||
errors.email ? ValidatedOptions.error : ValidatedOptions.default
|
||||
}
|
||||
isRequired
|
||||
>
|
||||
<TextInput
|
||||
data-testid="value-input"
|
||||
ref={register({ required: true })}
|
||||
autoFocus
|
||||
type="text"
|
||||
id="add-value"
|
||||
name="value"
|
||||
validated={
|
||||
errors.email ? ValidatedOptions.error : ValidatedOptions.default
|
||||
}
|
||||
/>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
</Modal>
|
||||
);
|
||||
};
|
|
@ -32,18 +32,20 @@ import type ComponentTypeRepresentation from "keycloak-admin/lib/defs/componentT
|
|||
|
||||
import "./RealmSettingsSection.css";
|
||||
import { useServerInfo } from "../context/server-info/ServerInfoProvider";
|
||||
import { AESGeneratedModal } from "./AESGeneratedModal";
|
||||
import { ECDSAGeneratedModal } from "./ECDSAGeneratedModal";
|
||||
import { HMACGeneratedModal } from "./HMACGeneratedModal";
|
||||
import { JavaKeystoreModal } from "./JavaKeystoreModal";
|
||||
import { RSAModal } from "./RSAModal";
|
||||
import { RSAGeneratedModal } from "./RSAGeneratedModal";
|
||||
import { useAdminClient } from "../context/auth/AdminClient";
|
||||
import { useAlerts } from "../components/alert/Alerts";
|
||||
import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog";
|
||||
import { useRealm } from "../context/realm-context/RealmContext";
|
||||
import { Link, useRouteMatch } from "react-router-dom";
|
||||
import { AESGeneratedModal } from "./AESGeneratedModal";
|
||||
import { JavaKeystoreModal } from "./JavaKeystoreModal";
|
||||
import { HMACGeneratedModal } from "./HMACGeneratedModal";
|
||||
import { ECDSAGeneratedModal } from "./ECDSAGeneratedModal";
|
||||
import { RSAModal } from "./RSAModal";
|
||||
import { RSAGeneratedModal } from "./RSAGeneratedModal";
|
||||
|
||||
type ComponentData = KeyMetadataRepresentation & {
|
||||
id?: string;
|
||||
providerDescription?: string;
|
||||
name?: string;
|
||||
toggleHidden?: boolean;
|
||||
|
@ -62,6 +64,7 @@ export const KeysTabInner = ({ components, refresh }: KeysTabInnerProps) => {
|
|||
const { addAlert } = useAlerts();
|
||||
const adminClient = useAdminClient();
|
||||
const { realm } = useRealm();
|
||||
const { url } = useRouteMatch();
|
||||
|
||||
const [id, setId] = useState("");
|
||||
|
||||
|
@ -335,9 +338,18 @@ export const KeysTabInner = ({ components, refresh }: KeysTabInnerProps) => {
|
|||
</DataListControl>
|
||||
<DataListItemCells
|
||||
dataListCells={[
|
||||
<DataListCell key={`name-${idx}`}>
|
||||
<DataListCell
|
||||
data-testId="provider-name"
|
||||
key={`name-${idx}`}
|
||||
>
|
||||
<>
|
||||
<Button variant="link">{component.name}</Button>
|
||||
<Link
|
||||
key={component.name}
|
||||
data-testId="provider-name-link"
|
||||
to={`${url}/${component.id}/${component.providerId}/settings`}
|
||||
>
|
||||
{component.name}
|
||||
</Link>
|
||||
</>
|
||||
</DataListCell>,
|
||||
<DataListCell key={`providerId-${idx}`}>
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Controller, useFormContext, useWatch } from "react-hook-form";
|
||||
import { Controller, useForm, useFormContext, useWatch } from "react-hook-form";
|
||||
import {
|
||||
ActionGroup,
|
||||
AlertVariant,
|
||||
Button,
|
||||
FormGroup,
|
||||
PageSection,
|
||||
|
@ -20,6 +21,8 @@ import { FormPanel } from "../components/scroll-form/FormPanel";
|
|||
import { KeycloakDataTable } from "../components/table-toolbar/KeycloakDataTable";
|
||||
import { useAdminClient } from "../context/auth/AdminClient";
|
||||
import { ListEmptyState } from "../components/list-empty-state/ListEmptyState";
|
||||
import { AddMessageBundleModal } from "./AddMessageBundleModal";
|
||||
import { useAlerts } from "../components/alert/Alerts";
|
||||
|
||||
type LocalizationTabProps = {
|
||||
save: (realm: RealmRepresentation) => void;
|
||||
|
@ -28,13 +31,23 @@ type LocalizationTabProps = {
|
|||
realm: RealmRepresentation;
|
||||
};
|
||||
|
||||
export type KeyValueType = { key: string; value: string };
|
||||
|
||||
export type BundleForm = {
|
||||
messageBundle: KeyValueType;
|
||||
};
|
||||
|
||||
export const LocalizationTab = ({
|
||||
save,
|
||||
reset,
|
||||
realm,
|
||||
refresh,
|
||||
}: LocalizationTabProps) => {
|
||||
const { t } = useTranslation("realm-settings");
|
||||
const adminClient = useAdminClient();
|
||||
const [addMessageBundleModalOpen, setAddMessageBundleModalOpen] = useState(
|
||||
false
|
||||
);
|
||||
const [key, setKey] = useState(0);
|
||||
|
||||
const [supportedLocalesOpen, setSupportedLocalesOpen] = useState(false);
|
||||
|
@ -43,6 +56,10 @@ export const LocalizationTab = ({
|
|||
const { getValues, control, handleSubmit } = useFormContext();
|
||||
const [valueSelected, setValueSelected] = useState(false);
|
||||
const themeTypes = useServerInfo().themes!;
|
||||
const bundleForm = useForm<BundleForm>({ mode: "onChange" });
|
||||
const { addAlert } = useAlerts();
|
||||
|
||||
console.log(realm.supportedLocales);
|
||||
|
||||
const watchSupportedLocales = useWatch({
|
||||
control,
|
||||
|
@ -56,19 +73,68 @@ export const LocalizationTab = ({
|
|||
defaultValue: realm?.internationalizationEnabled,
|
||||
});
|
||||
|
||||
console.log("ok", realm);
|
||||
|
||||
const loader = async () => {
|
||||
if (realm) {
|
||||
// if(realm.supportedLocales?.length === 0) {
|
||||
// return [[]];
|
||||
// }
|
||||
// else {
|
||||
const result = await adminClient.realms.getRealmLocalizationTexts({
|
||||
realm: realm.realm!,
|
||||
selectedLocale: getValues("defaultLocale") || "en",
|
||||
});
|
||||
return Object.keys(result).map((key) => [key, result[key]]);
|
||||
}
|
||||
|
||||
// }
|
||||
return [[]];
|
||||
};
|
||||
|
||||
const handleModalToggle = () => {
|
||||
setAddMessageBundleModalOpen(!addMessageBundleModalOpen);
|
||||
};
|
||||
|
||||
const addKeyValue = async (pair: KeyValueType): Promise<void> => {
|
||||
try {
|
||||
adminClient.setConfig({
|
||||
requestConfig: { headers: { "Content-Type": "text/plain" } },
|
||||
});
|
||||
await adminClient.realms.addLocalization(
|
||||
{
|
||||
realm: realm.realm!,
|
||||
selectedLocale: getValues("defaultLocale") || "en",
|
||||
key: pair.key,
|
||||
},
|
||||
pair.value
|
||||
);
|
||||
|
||||
adminClient.setConfig({
|
||||
realmName: realm.realm,
|
||||
});
|
||||
refresh();
|
||||
addAlert(t("realm-settings:pairCreatedSuccess"), AlertVariant.success);
|
||||
} catch (error) {
|
||||
addAlert(
|
||||
t("realm-settings:pairCreatedError", { error }),
|
||||
AlertVariant.danger
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{addMessageBundleModalOpen && (
|
||||
<AddMessageBundleModal
|
||||
handleModalToggle={handleModalToggle}
|
||||
save={(pair: any) => {
|
||||
addKeyValue(pair);
|
||||
handleModalToggle();
|
||||
}}
|
||||
form={bundleForm}
|
||||
/>
|
||||
)}
|
||||
<PageSection variant="light">
|
||||
<FormPanel
|
||||
className="kc-login-screen"
|
||||
|
@ -236,13 +302,22 @@ export const LocalizationTab = ({
|
|||
key={key}
|
||||
loader={loader}
|
||||
ariaLabelKey="client-scopes:clientScopeList"
|
||||
toolbarItem={
|
||||
<Button
|
||||
data-testid="add-bundle-button"
|
||||
onClick={() => setAddMessageBundleModalOpen(true)}
|
||||
>
|
||||
{t("addMessageBundle")}
|
||||
</Button>
|
||||
}
|
||||
searchPlaceholderKey=" "
|
||||
emptyState={
|
||||
<ListEmptyState
|
||||
hasIcon={true}
|
||||
message={t("noMessageBundles")}
|
||||
instructions={t("noMessageBundlesInstructions")}
|
||||
onPrimaryAction={() => {}}
|
||||
onPrimaryAction={handleModalToggle}
|
||||
primaryActionText={t("addMessageBundle")}
|
||||
/>
|
||||
}
|
||||
canSelectAll
|
||||
|
|
|
@ -317,6 +317,7 @@ export const RealmSettingsSection = () => {
|
|||
<Tab
|
||||
id="localization"
|
||||
eventKey="localization"
|
||||
data-testid="rs-localization-tab"
|
||||
title={<TabTitleText>{t("localization")}</TabTitleText>}
|
||||
>
|
||||
<LocalizationTab
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
"deleteError": "Could not delete realm: {{error}}",
|
||||
"disableConfirmTitle": "Disable realm?",
|
||||
"disableConfirm": "User and clients can't access the realm if it's disabled. Are you sure you want to continue?",
|
||||
"editProvider": "Edit provider",
|
||||
"saveSuccess": "Realm successfully updated",
|
||||
"saveProviderSuccess": "The provider has been saved successfully.",
|
||||
"saveProviderError": "Error saving provider: ",
|
||||
|
@ -69,6 +70,7 @@
|
|||
"secretSize": "Secret size",
|
||||
"type": "Type",
|
||||
"name": "Name",
|
||||
"providerId": "ID",
|
||||
"kid": "Kid",
|
||||
"provider": "Provider",
|
||||
"providerDescription": "Provider description",
|
||||
|
@ -145,9 +147,11 @@
|
|||
"localization": "Localization",
|
||||
"key": "Key",
|
||||
"value": "Value",
|
||||
"pairCreatedSuccess": "Success! The localization text has been created.",
|
||||
"pairCreatedError": "Error creating localization text.",
|
||||
"supportedLocales": "Supported locales",
|
||||
"defaultLocale": "Default locale",
|
||||
|
||||
"addMessageBundle": "Add message bundle",
|
||||
"eventType": "Event saved type",
|
||||
"searchEventType": "Search saved event type",
|
||||
"addSavedTypes": "Add saved types",
|
||||
|
|
Loading…
Reference in a new issue