Add RoutableTabs component for routed tabs (#1852)
This commit is contained in:
parent
811131518e
commit
919d07c90b
6 changed files with 186 additions and 69 deletions
|
@ -197,7 +197,7 @@ describe("Realm settings events tab tests", () => {
|
||||||
|
|
||||||
it("Realm header settings", () => {
|
it("Realm header settings", () => {
|
||||||
sidebarPage.goToRealmSettings();
|
sidebarPage.goToRealmSettings();
|
||||||
cy.get("#pf-tab-securityDefences-securityDefences").click();
|
cy.findByTestId("rs-security-defenses-tab").click();
|
||||||
cy.findByTestId("headers-form-tab-save").should("be.disabled");
|
cy.findByTestId("headers-form-tab-save").should("be.disabled");
|
||||||
cy.get("#xFrameOptions").clear().type("DENY");
|
cy.get("#xFrameOptions").clear().type("DENY");
|
||||||
cy.findByTestId("headers-form-tab-save").should("be.enabled").click();
|
cy.findByTestId("headers-form-tab-save").should("be.enabled").click();
|
||||||
|
@ -207,7 +207,7 @@ describe("Realm settings events tab tests", () => {
|
||||||
|
|
||||||
it("Brute force detection", () => {
|
it("Brute force detection", () => {
|
||||||
sidebarPage.goToRealmSettings();
|
sidebarPage.goToRealmSettings();
|
||||||
cy.get("#pf-tab-securityDefences-securityDefences").click();
|
cy.findAllByTestId("rs-security-defenses-tab").click();
|
||||||
cy.get("#pf-tab-20-bruteForce").click();
|
cy.get("#pf-tab-20-bruteForce").click();
|
||||||
|
|
||||||
cy.findByTestId("brute-force-tab-save").should("be.disabled");
|
cy.findByTestId("brute-force-tab-save").should("be.disabled");
|
||||||
|
|
62
package-lock.json
generated
62
package-lock.json
generated
|
@ -10,7 +10,7 @@
|
||||||
"@keycloak/keycloak-admin-client": "^17.0.0-dev.11",
|
"@keycloak/keycloak-admin-client": "^17.0.0-dev.11",
|
||||||
"@patternfly/patternfly": "^4.164.2",
|
"@patternfly/patternfly": "^4.164.2",
|
||||||
"@patternfly/react-code-editor": "^4.22.1",
|
"@patternfly/react-code-editor": "^4.22.1",
|
||||||
"@patternfly/react-core": "^4.181.1",
|
"@patternfly/react-core": "^4.183.10",
|
||||||
"@patternfly/react-icons": "^4.32.1",
|
"@patternfly/react-icons": "^4.32.1",
|
||||||
"@patternfly/react-table": "^4.50.1",
|
"@patternfly/react-table": "^4.50.1",
|
||||||
"dagre": "^0.8.5",
|
"dagre": "^0.8.5",
|
||||||
|
@ -3714,13 +3714,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@patternfly/react-core": {
|
"node_modules/@patternfly/react-core": {
|
||||||
"version": "4.181.1",
|
"version": "4.183.10",
|
||||||
"resolved": "https://registry.npmjs.org/@patternfly/react-core/-/react-core-4.181.1.tgz",
|
"resolved": "https://registry.npmjs.org/@patternfly/react-core/-/react-core-4.183.10.tgz",
|
||||||
"integrity": "sha512-5pt4R8Cg8CkA6xCY4v6wurpwn8WIS8N8NqQEtp56WABMVpZC+TE7k1TSsrDDR1WhJlxsl48VbsANkwMYLlsSJg==",
|
"integrity": "sha512-d87q/WCvqWYMffq+zqRuNWXUWx6nQRdrJucJBhmjnYGnyQm9Agr0EgqBFyjQA8cnk+uTubCC+wYsmjDdDMUm1A==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@patternfly/react-icons": "^4.32.1",
|
"@patternfly/react-icons": "^4.34.10",
|
||||||
"@patternfly/react-styles": "^4.31.1",
|
"@patternfly/react-styles": "^4.33.10",
|
||||||
"@patternfly/react-tokens": "^4.33.1",
|
"@patternfly/react-tokens": "^4.35.10",
|
||||||
"focus-trap": "6.2.2",
|
"focus-trap": "6.2.2",
|
||||||
"react-dropzone": "9.0.0",
|
"react-dropzone": "9.0.0",
|
||||||
"tippy.js": "5.1.2",
|
"tippy.js": "5.1.2",
|
||||||
|
@ -3732,18 +3732,18 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@patternfly/react-icons": {
|
"node_modules/@patternfly/react-icons": {
|
||||||
"version": "4.32.1",
|
"version": "4.34.10",
|
||||||
"resolved": "https://registry.npmjs.org/@patternfly/react-icons/-/react-icons-4.32.1.tgz",
|
"resolved": "https://registry.npmjs.org/@patternfly/react-icons/-/react-icons-4.34.10.tgz",
|
||||||
"integrity": "sha512-E7Fpnvax37e2ow8Xc2GngQBM7IuOpRyphZXCIUAk/NGsqpvFX27YhIVZiOUIAuBXAI5VXQBwueW/tmhmlXP7+w==",
|
"integrity": "sha512-oEDFfyzBWeMO9EQYC2P5MrvR6mxq/kaQKHoC8xFbY449HnC3aloT+dk5kvMqpjcjV2teCSV/qE/4K+m9XZVm9w==",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^16.8.0 || ^17.0.0",
|
"react": "^16.8.0 || ^17.0.0",
|
||||||
"react-dom": "^16.8.0 || ^17.0.0"
|
"react-dom": "^16.8.0 || ^17.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@patternfly/react-styles": {
|
"node_modules/@patternfly/react-styles": {
|
||||||
"version": "4.31.1",
|
"version": "4.33.10",
|
||||||
"resolved": "https://registry.npmjs.org/@patternfly/react-styles/-/react-styles-4.31.1.tgz",
|
"resolved": "https://registry.npmjs.org/@patternfly/react-styles/-/react-styles-4.33.10.tgz",
|
||||||
"integrity": "sha512-Yw2hgg3T2qEqPYej5xprYD0iTTkzFMNjaF8u/YFyZOBNwfhjK8QQDZx8Du7Z6em8zGtajXFG5rZqxDiiz8bDfQ=="
|
"integrity": "sha512-pMvpJmQyLRrqlspxp8CPgbIWquEdH/zIBHOQj5XWc8Zk83tZxYi+9tLyTO+RxG5kvtUVxsP+3vncrGxqmmzlQA=="
|
||||||
},
|
},
|
||||||
"node_modules/@patternfly/react-table": {
|
"node_modules/@patternfly/react-table": {
|
||||||
"version": "4.50.1",
|
"version": "4.50.1",
|
||||||
|
@ -3763,9 +3763,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@patternfly/react-tokens": {
|
"node_modules/@patternfly/react-tokens": {
|
||||||
"version": "4.33.1",
|
"version": "4.35.10",
|
||||||
"resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-4.33.1.tgz",
|
"resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-4.35.10.tgz",
|
||||||
"integrity": "sha512-n06+BYDviOEuoo+qE9f0Jm1DkMDpwtXWyaJFHsvi8w8uddQEsBGGoP7lpkwZj15u6jc+F9IDgk/j+EkTScrvUA=="
|
"integrity": "sha512-yb2m8tsLeWr5oU7UGh2NUcrJ+V6vZrGroerYMwFvcCzh1GWmxOU1ElYlsSdt+TPPLv+ZscbpSlolQmrQtAaueg=="
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/plugin-commonjs": {
|
"node_modules/@rollup/plugin-commonjs": {
|
||||||
"version": "16.0.0",
|
"version": "16.0.0",
|
||||||
|
@ -24191,13 +24191,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@patternfly/react-core": {
|
"@patternfly/react-core": {
|
||||||
"version": "4.181.1",
|
"version": "4.183.10",
|
||||||
"resolved": "https://registry.npmjs.org/@patternfly/react-core/-/react-core-4.181.1.tgz",
|
"resolved": "https://registry.npmjs.org/@patternfly/react-core/-/react-core-4.183.10.tgz",
|
||||||
"integrity": "sha512-5pt4R8Cg8CkA6xCY4v6wurpwn8WIS8N8NqQEtp56WABMVpZC+TE7k1TSsrDDR1WhJlxsl48VbsANkwMYLlsSJg==",
|
"integrity": "sha512-d87q/WCvqWYMffq+zqRuNWXUWx6nQRdrJucJBhmjnYGnyQm9Agr0EgqBFyjQA8cnk+uTubCC+wYsmjDdDMUm1A==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@patternfly/react-icons": "^4.32.1",
|
"@patternfly/react-icons": "^4.34.10",
|
||||||
"@patternfly/react-styles": "^4.31.1",
|
"@patternfly/react-styles": "^4.33.10",
|
||||||
"@patternfly/react-tokens": "^4.33.1",
|
"@patternfly/react-tokens": "^4.35.10",
|
||||||
"focus-trap": "6.2.2",
|
"focus-trap": "6.2.2",
|
||||||
"react-dropzone": "9.0.0",
|
"react-dropzone": "9.0.0",
|
||||||
"tippy.js": "5.1.2",
|
"tippy.js": "5.1.2",
|
||||||
|
@ -24205,15 +24205,15 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@patternfly/react-icons": {
|
"@patternfly/react-icons": {
|
||||||
"version": "4.32.1",
|
"version": "4.34.10",
|
||||||
"resolved": "https://registry.npmjs.org/@patternfly/react-icons/-/react-icons-4.32.1.tgz",
|
"resolved": "https://registry.npmjs.org/@patternfly/react-icons/-/react-icons-4.34.10.tgz",
|
||||||
"integrity": "sha512-E7Fpnvax37e2ow8Xc2GngQBM7IuOpRyphZXCIUAk/NGsqpvFX27YhIVZiOUIAuBXAI5VXQBwueW/tmhmlXP7+w==",
|
"integrity": "sha512-oEDFfyzBWeMO9EQYC2P5MrvR6mxq/kaQKHoC8xFbY449HnC3aloT+dk5kvMqpjcjV2teCSV/qE/4K+m9XZVm9w==",
|
||||||
"requires": {}
|
"requires": {}
|
||||||
},
|
},
|
||||||
"@patternfly/react-styles": {
|
"@patternfly/react-styles": {
|
||||||
"version": "4.31.1",
|
"version": "4.33.10",
|
||||||
"resolved": "https://registry.npmjs.org/@patternfly/react-styles/-/react-styles-4.31.1.tgz",
|
"resolved": "https://registry.npmjs.org/@patternfly/react-styles/-/react-styles-4.33.10.tgz",
|
||||||
"integrity": "sha512-Yw2hgg3T2qEqPYej5xprYD0iTTkzFMNjaF8u/YFyZOBNwfhjK8QQDZx8Du7Z6em8zGtajXFG5rZqxDiiz8bDfQ=="
|
"integrity": "sha512-pMvpJmQyLRrqlspxp8CPgbIWquEdH/zIBHOQj5XWc8Zk83tZxYi+9tLyTO+RxG5kvtUVxsP+3vncrGxqmmzlQA=="
|
||||||
},
|
},
|
||||||
"@patternfly/react-table": {
|
"@patternfly/react-table": {
|
||||||
"version": "4.50.1",
|
"version": "4.50.1",
|
||||||
|
@ -24229,9 +24229,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@patternfly/react-tokens": {
|
"@patternfly/react-tokens": {
|
||||||
"version": "4.33.1",
|
"version": "4.35.10",
|
||||||
"resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-4.33.1.tgz",
|
"resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-4.35.10.tgz",
|
||||||
"integrity": "sha512-n06+BYDviOEuoo+qE9f0Jm1DkMDpwtXWyaJFHsvi8w8uddQEsBGGoP7lpkwZj15u6jc+F9IDgk/j+EkTScrvUA=="
|
"integrity": "sha512-yb2m8tsLeWr5oU7UGh2NUcrJ+V6vZrGroerYMwFvcCzh1GWmxOU1ElYlsSdt+TPPLv+ZscbpSlolQmrQtAaueg=="
|
||||||
},
|
},
|
||||||
"@rollup/plugin-commonjs": {
|
"@rollup/plugin-commonjs": {
|
||||||
"version": "16.0.0",
|
"version": "16.0.0",
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
"@keycloak/keycloak-admin-client": "^17.0.0-dev.11",
|
"@keycloak/keycloak-admin-client": "^17.0.0-dev.11",
|
||||||
"@patternfly/patternfly": "^4.164.2",
|
"@patternfly/patternfly": "^4.164.2",
|
||||||
"@patternfly/react-code-editor": "^4.22.1",
|
"@patternfly/react-code-editor": "^4.22.1",
|
||||||
"@patternfly/react-core": "^4.181.1",
|
"@patternfly/react-core": "^4.183.10",
|
||||||
"@patternfly/react-icons": "^4.32.1",
|
"@patternfly/react-icons": "^4.32.1",
|
||||||
"@patternfly/react-table": "^4.50.1",
|
"@patternfly/react-table": "^4.50.1",
|
||||||
"dagre": "^0.8.5",
|
"dagre": "^0.8.5",
|
||||||
|
|
70
src/components/routable-tabs/RoutableTabs.tsx
Normal file
70
src/components/routable-tabs/RoutableTabs.tsx
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
import {
|
||||||
|
TabProps,
|
||||||
|
Tabs,
|
||||||
|
TabsComponent,
|
||||||
|
TabsProps,
|
||||||
|
} from "@patternfly/react-core";
|
||||||
|
import type { History, LocationDescriptorObject } from "history";
|
||||||
|
import React, {
|
||||||
|
Children,
|
||||||
|
isValidElement,
|
||||||
|
JSXElementConstructor,
|
||||||
|
ReactElement,
|
||||||
|
} from "react";
|
||||||
|
import { useLocation } from "react-router-dom";
|
||||||
|
|
||||||
|
type ChildElement = ReactElement<TabProps, JSXElementConstructor<TabProps>>;
|
||||||
|
type Child = ChildElement | boolean | null | undefined;
|
||||||
|
|
||||||
|
// TODO: Figure out why we need to omit 'ref' from the props.
|
||||||
|
type RoutableTabsProps = { children: Child | Child[] } & Omit<
|
||||||
|
TabsProps,
|
||||||
|
"ref" | "activeKey" | "component" | "children"
|
||||||
|
>;
|
||||||
|
|
||||||
|
export const RoutableTabs = ({
|
||||||
|
children,
|
||||||
|
...otherProps
|
||||||
|
}: RoutableTabsProps) => {
|
||||||
|
const { pathname } = useLocation();
|
||||||
|
|
||||||
|
// Extract event keys from children.
|
||||||
|
const eventKeys = Children.toArray(children)
|
||||||
|
.filter((child): child is ChildElement => isValidElement(child))
|
||||||
|
.map((child) => child.props.eventKey.toString());
|
||||||
|
|
||||||
|
// Determine if there is an exact match.
|
||||||
|
const exactMatch = eventKeys.find((eventKey) => eventKey === pathname);
|
||||||
|
|
||||||
|
// Determine which event keys at least partially match the current path, then sort them so the nearest match ends up on top.
|
||||||
|
const nearestMatch = eventKeys
|
||||||
|
.filter((eventKey) => pathname.includes(eventKey))
|
||||||
|
.sort((a, b) => a.length - b.length)
|
||||||
|
.pop();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Tabs
|
||||||
|
activeKey={exactMatch ?? nearestMatch ?? pathname}
|
||||||
|
component={TabsComponent.nav}
|
||||||
|
inset={{
|
||||||
|
default: "insetNone",
|
||||||
|
md: "insetSm",
|
||||||
|
xl: "inset2xl",
|
||||||
|
"2xl": "insetLg",
|
||||||
|
}}
|
||||||
|
{...otherProps}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Tabs>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
type RoutableTabParams = {
|
||||||
|
to: LocationDescriptorObject;
|
||||||
|
history: History<unknown>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const routableTab = ({ to, history }: RoutableTabParams) => ({
|
||||||
|
eventKey: to.pathname ?? "",
|
||||||
|
href: history.createHref(to),
|
||||||
|
});
|
|
@ -17,7 +17,10 @@ import type RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/r
|
||||||
import type ComponentRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentRepresentation";
|
import type ComponentRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentRepresentation";
|
||||||
|
|
||||||
import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog";
|
import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog";
|
||||||
import { KeycloakTabs } from "../components/keycloak-tabs/KeycloakTabs";
|
import {
|
||||||
|
routableTab,
|
||||||
|
RoutableTabs,
|
||||||
|
} from "../components/routable-tabs/RoutableTabs";
|
||||||
import { useRealm } from "../context/realm-context/RealmContext";
|
import { useRealm } from "../context/realm-context/RealmContext";
|
||||||
import { useRealms } from "../context/RealmsContext";
|
import { useRealms } from "../context/RealmsContext";
|
||||||
import { ViewHeader } from "../components/view-header/ViewHeader";
|
import { ViewHeader } from "../components/view-header/ViewHeader";
|
||||||
|
@ -247,12 +250,14 @@ export const RealmSettingsTabs = ({
|
||||||
/>
|
/>
|
||||||
<PageSection variant="light" className="pf-u-p-0">
|
<PageSection variant="light" className="pf-u-p-0">
|
||||||
<FormProvider {...form}>
|
<FormProvider {...form}>
|
||||||
<KeycloakTabs isBox mountOnEnter>
|
<RoutableTabs isBox mountOnEnter>
|
||||||
<Tab
|
<Tab
|
||||||
eventKey="general"
|
|
||||||
title={<TabTitleText>{t("general")}</TabTitleText>}
|
title={<TabTitleText>{t("general")}</TabTitleText>}
|
||||||
data-testid="rs-general-tab"
|
data-testid="rs-general-tab"
|
||||||
aria-label="general-tab"
|
{...routableTab({
|
||||||
|
to: toRealmSettings({ realm: realmName }),
|
||||||
|
history,
|
||||||
|
})}
|
||||||
>
|
>
|
||||||
<RealmSettingsGeneralTab
|
<RealmSettingsGeneralTab
|
||||||
save={save}
|
save={save}
|
||||||
|
@ -260,10 +265,12 @@ export const RealmSettingsTabs = ({
|
||||||
/>
|
/>
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab
|
<Tab
|
||||||
eventKey="login"
|
|
||||||
title={<TabTitleText>{t("login")}</TabTitleText>}
|
title={<TabTitleText>{t("login")}</TabTitleText>}
|
||||||
data-testid="rs-login-tab"
|
data-testid="rs-login-tab"
|
||||||
aria-label="login-tab"
|
{...routableTab({
|
||||||
|
to: toRealmSettings({ realm: realmName, tab: "login" }),
|
||||||
|
history,
|
||||||
|
})}
|
||||||
>
|
>
|
||||||
<RealmSettingsLoginTab
|
<RealmSettingsLoginTab
|
||||||
refresh={refresh}
|
refresh={refresh}
|
||||||
|
@ -272,18 +279,22 @@ export const RealmSettingsTabs = ({
|
||||||
/>
|
/>
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab
|
<Tab
|
||||||
eventKey="email"
|
|
||||||
title={<TabTitleText>{t("email")}</TabTitleText>}
|
title={<TabTitleText>{t("email")}</TabTitleText>}
|
||||||
data-testid="rs-email-tab"
|
data-testid="rs-email-tab"
|
||||||
aria-label="email-tab"
|
{...routableTab({
|
||||||
|
to: toRealmSettings({ realm: realmName, tab: "email" }),
|
||||||
|
history,
|
||||||
|
})}
|
||||||
>
|
>
|
||||||
<RealmSettingsEmailTab realm={realm} />
|
<RealmSettingsEmailTab realm={realm} />
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab
|
<Tab
|
||||||
eventKey="themes"
|
|
||||||
title={<TabTitleText>{t("themes")}</TabTitleText>}
|
title={<TabTitleText>{t("themes")}</TabTitleText>}
|
||||||
data-testid="rs-themes-tab"
|
data-testid="rs-themes-tab"
|
||||||
aria-label="themes-tab"
|
{...routableTab({
|
||||||
|
to: toRealmSettings({ realm: realmName, tab: "themes" }),
|
||||||
|
history,
|
||||||
|
})}
|
||||||
>
|
>
|
||||||
<RealmSettingsThemesTab
|
<RealmSettingsThemesTab
|
||||||
save={save}
|
save={save}
|
||||||
|
@ -291,10 +302,12 @@ export const RealmSettingsTabs = ({
|
||||||
/>
|
/>
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab
|
<Tab
|
||||||
eventKey="keys"
|
|
||||||
title={<TabTitleText>{t("realm-settings:keys")}</TabTitleText>}
|
title={<TabTitleText>{t("realm-settings:keys")}</TabTitleText>}
|
||||||
data-testid="rs-keys-tab"
|
data-testid="rs-keys-tab"
|
||||||
aria-label="keys-tab"
|
{...routableTab({
|
||||||
|
to: toRealmSettings({ realm: realmName, tab: "keys" }),
|
||||||
|
history,
|
||||||
|
})}
|
||||||
>
|
>
|
||||||
<Tabs
|
<Tabs
|
||||||
activeKey={activeTab}
|
activeKey={activeTab}
|
||||||
|
@ -325,18 +338,22 @@ export const RealmSettingsTabs = ({
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab
|
<Tab
|
||||||
eventKey="events"
|
|
||||||
title={<TabTitleText>{t("events")}</TabTitleText>}
|
title={<TabTitleText>{t("events")}</TabTitleText>}
|
||||||
data-testid="rs-realm-events-tab"
|
data-testid="rs-realm-events-tab"
|
||||||
aria-label="realm-events-tab"
|
{...routableTab({
|
||||||
|
to: toRealmSettings({ realm: realmName, tab: "events" }),
|
||||||
|
history,
|
||||||
|
})}
|
||||||
>
|
>
|
||||||
<EventsTab />
|
<EventsTab />
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab
|
<Tab
|
||||||
id="localization"
|
|
||||||
eventKey="localization"
|
|
||||||
data-testid="rs-localization-tab"
|
|
||||||
title={<TabTitleText>{t("localization")}</TabTitleText>}
|
title={<TabTitleText>{t("localization")}</TabTitleText>}
|
||||||
|
data-testid="rs-localization-tab"
|
||||||
|
{...routableTab({
|
||||||
|
to: toRealmSettings({ realm: realmName, tab: "localization" }),
|
||||||
|
history,
|
||||||
|
})}
|
||||||
>
|
>
|
||||||
<LocalizationTab
|
<LocalizationTab
|
||||||
key={key}
|
key={key}
|
||||||
|
@ -347,29 +364,43 @@ export const RealmSettingsTabs = ({
|
||||||
/>
|
/>
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab
|
<Tab
|
||||||
id="securityDefences"
|
|
||||||
eventKey="securityDefences"
|
|
||||||
title={<TabTitleText>{t("securityDefences")}</TabTitleText>}
|
title={<TabTitleText>{t("securityDefences")}</TabTitleText>}
|
||||||
|
data-testid="rs-security-defenses-tab"
|
||||||
|
{...routableTab({
|
||||||
|
to: toRealmSettings({
|
||||||
|
realm: realmName,
|
||||||
|
tab: "securityDefences",
|
||||||
|
}),
|
||||||
|
history,
|
||||||
|
})}
|
||||||
>
|
>
|
||||||
<SecurityDefences save={save} reset={() => resetForm(realm)} />
|
<SecurityDefences save={save} reset={() => resetForm(realm)} />
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab
|
<Tab
|
||||||
id="sessions"
|
|
||||||
eventKey="sessions"
|
|
||||||
data-testid="rs-sessions-tab"
|
|
||||||
aria-label="sessions-tab"
|
|
||||||
title={
|
title={
|
||||||
<TabTitleText>{t("realm-settings:sessions")}</TabTitleText>
|
<TabTitleText>{t("realm-settings:sessions")}</TabTitleText>
|
||||||
}
|
}
|
||||||
|
data-testid="rs-sessions-tab"
|
||||||
|
{...routableTab({
|
||||||
|
to: toRealmSettings({
|
||||||
|
realm: realmName,
|
||||||
|
tab: "sessions",
|
||||||
|
}),
|
||||||
|
history,
|
||||||
|
})}
|
||||||
>
|
>
|
||||||
<RealmSettingsSessionsTab key={key} realm={realm} save={save} />
|
<RealmSettingsSessionsTab key={key} realm={realm} save={save} />
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab
|
<Tab
|
||||||
id="tokens"
|
|
||||||
eventKey="tokens"
|
|
||||||
data-testid="rs-tokens-tab"
|
|
||||||
aria-label="tokens-tab"
|
|
||||||
title={<TabTitleText>{t("realm-settings:tokens")}</TabTitleText>}
|
title={<TabTitleText>{t("realm-settings:tokens")}</TabTitleText>}
|
||||||
|
data-testid="rs-tokens-tab"
|
||||||
|
{...routableTab({
|
||||||
|
to: toRealmSettings({
|
||||||
|
realm: realmName,
|
||||||
|
tab: "tokens",
|
||||||
|
}),
|
||||||
|
history,
|
||||||
|
})}
|
||||||
>
|
>
|
||||||
<RealmSettingsTokensTab
|
<RealmSettingsTokensTab
|
||||||
save={save}
|
save={save}
|
||||||
|
@ -378,14 +409,19 @@ export const RealmSettingsTabs = ({
|
||||||
/>
|
/>
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab
|
<Tab
|
||||||
eventKey="clientPolicies"
|
|
||||||
title={
|
title={
|
||||||
<TabTitleText>
|
<TabTitleText>
|
||||||
{t("realm-settings:clientPolicies")}
|
{t("realm-settings:clientPolicies")}
|
||||||
</TabTitleText>
|
</TabTitleText>
|
||||||
}
|
}
|
||||||
data-testid="rs-clientPolicies-tab"
|
data-testid="rs-clientPolicies-tab"
|
||||||
aria-label={t("clientPoliciesTab")}
|
{...routableTab({
|
||||||
|
to: toRealmSettings({
|
||||||
|
realm: realmName,
|
||||||
|
tab: "clientPolicies",
|
||||||
|
}),
|
||||||
|
history,
|
||||||
|
})}
|
||||||
>
|
>
|
||||||
<Tabs
|
<Tabs
|
||||||
activeKey={activeTab}
|
activeKey={activeTab}
|
||||||
|
@ -434,26 +470,37 @@ export const RealmSettingsTabs = ({
|
||||||
{isFeatureEnabled(Feature.DeclarativeUserProfile) &&
|
{isFeatureEnabled(Feature.DeclarativeUserProfile) &&
|
||||||
userProfileEnabled === "true" && (
|
userProfileEnabled === "true" && (
|
||||||
<Tab
|
<Tab
|
||||||
eventKey="userProfile"
|
|
||||||
data-testid="rs-user-profile-tab"
|
|
||||||
title={
|
title={
|
||||||
<TabTitleText>
|
<TabTitleText>
|
||||||
{t("realm-settings:userProfile")}
|
{t("realm-settings:userProfile")}
|
||||||
</TabTitleText>
|
</TabTitleText>
|
||||||
}
|
}
|
||||||
|
data-testid="rs-user-profile-tab"
|
||||||
|
{...routableTab({
|
||||||
|
to: toRealmSettings({
|
||||||
|
realm: realmName,
|
||||||
|
tab: "userProfile",
|
||||||
|
}),
|
||||||
|
history,
|
||||||
|
})}
|
||||||
>
|
>
|
||||||
<UserProfileTab />
|
<UserProfileTab />
|
||||||
</Tab>
|
</Tab>
|
||||||
)}
|
)}
|
||||||
<Tab
|
<Tab
|
||||||
eventKey="userRegistration"
|
|
||||||
title={<TabTitleText>{t("userRegistration")}</TabTitleText>}
|
title={<TabTitleText>{t("userRegistration")}</TabTitleText>}
|
||||||
data-testid="rs-userRegistration-tab"
|
data-testid="rs-userRegistration-tab"
|
||||||
aria-label={t("userRegistrationTab")}
|
{...routableTab({
|
||||||
|
to: toRealmSettings({
|
||||||
|
realm: realmName,
|
||||||
|
tab: "userRegistration",
|
||||||
|
}),
|
||||||
|
history,
|
||||||
|
})}
|
||||||
>
|
>
|
||||||
<UserRegistration />
|
<UserRegistration />
|
||||||
</Tab>
|
</Tab>
|
||||||
</KeycloakTabs>
|
</RoutableTabs>
|
||||||
</FormProvider>
|
</FormProvider>
|
||||||
</PageSection>
|
</PageSection>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -4,12 +4,12 @@ import { generatePath } from "react-router-dom";
|
||||||
import type { RouteDef } from "../../route-config";
|
import type { RouteDef } from "../../route-config";
|
||||||
|
|
||||||
export type RealmSettingsTab =
|
export type RealmSettingsTab =
|
||||||
| "general"
|
|
||||||
| "login"
|
| "login"
|
||||||
| "email"
|
| "email"
|
||||||
| "themes"
|
| "themes"
|
||||||
| "keys"
|
| "keys"
|
||||||
| "events"
|
| "events"
|
||||||
|
| "localization"
|
||||||
| "securityDefences"
|
| "securityDefences"
|
||||||
| "sessions"
|
| "sessions"
|
||||||
| "tokens"
|
| "tokens"
|
||||||
|
|
Loading…
Reference in a new issue