Changed to use routable tabs (#1934)
* Changed to use routable tabs * fixed tests
This commit is contained in:
parent
b9e79b6d75
commit
8b0327fa2c
16 changed files with 203 additions and 75 deletions
|
@ -73,7 +73,7 @@ describe("Clients SAML tests", () => {
|
||||||
loginPage.logIn();
|
loginPage.logIn();
|
||||||
sidebarPage.goToClients();
|
sidebarPage.goToClients();
|
||||||
listingPage.searchItem(clientId).goToItemDetails(clientId);
|
listingPage.searchItem(clientId).goToItemDetails(clientId);
|
||||||
cy.get("#pf-tab-keys-keys").click();
|
cy.findByTestId("keysTab").click();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("doesn't disable when no", () => {
|
it("doesn't disable when no", () => {
|
||||||
|
|
|
@ -279,7 +279,7 @@ describe("Clients test", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("add mapping to openid client", () => {
|
it("add mapping to openid client", () => {
|
||||||
cy.get("#pf-tab-mappers-mappers").click();
|
cy.findByTestId("mappersTab").click();
|
||||||
cy.findByText("Add predefined mapper").click();
|
cy.findByText("Add predefined mapper").click();
|
||||||
cy.get("table input").first().click();
|
cy.get("table input").first().click();
|
||||||
cy.findByTestId("modalConfirm").click();
|
cy.findByTestId("modalConfirm").click();
|
||||||
|
@ -343,15 +343,13 @@ describe("Clients test", () => {
|
||||||
|
|
||||||
it("displays the correct tabs", () => {
|
it("displays the correct tabs", () => {
|
||||||
cy.findByTestId("client-tabs")
|
cy.findByTestId("client-tabs")
|
||||||
.find("#pf-tab-settings-settings")
|
.findByTestId("clientSettingsTab")
|
||||||
.should("exist");
|
.should("exist");
|
||||||
|
|
||||||
cy.findByTestId("client-tabs")
|
cy.findByTestId("client-tabs").findByTestId("rolesTab").should("exist");
|
||||||
.find("#pf-tab-roles-roles")
|
|
||||||
.should("exist");
|
|
||||||
|
|
||||||
cy.findByTestId("client-tabs")
|
cy.findByTestId("client-tabs")
|
||||||
.find("#pf-tab-advanced-advanced")
|
.findByTestId("advancedTab")
|
||||||
.should("exist");
|
.should("exist");
|
||||||
|
|
||||||
cy.findByTestId("client-tabs").find("li").should("have.length", 3);
|
cy.findByTestId("client-tabs").find("li").should("have.length", 3);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
export default class RoleMappingTab {
|
export default class RoleMappingTab {
|
||||||
private tab = "#pf-tab-serviceAccount-serviceAccount";
|
private tab = "serviceAccountTab";
|
||||||
private scopeTab = "scopeTab";
|
private scopeTab = "scopeTab";
|
||||||
private assignEmptyRoleBtn = "no-roles-for-this-client-empty-action";
|
private assignEmptyRoleBtn = "no-roles-for-this-client-empty-action";
|
||||||
private assignRoleBtn = "assignRole";
|
private assignRoleBtn = "assignRole";
|
||||||
|
@ -12,7 +12,7 @@ export default class RoleMappingTab {
|
||||||
private confirmModalBtn = "modalConfirm";
|
private confirmModalBtn = "modalConfirm";
|
||||||
|
|
||||||
goToServiceAccountTab() {
|
goToServiceAccountTab() {
|
||||||
cy.get(this.tab).click();
|
cy.findByTestId(this.tab).click();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,10 +17,10 @@ export default class AdvancedTab {
|
||||||
private fineGrainSaveBtn = "#fineGrainSave";
|
private fineGrainSaveBtn = "#fineGrainSave";
|
||||||
private fineGrainRevertBtn = "#fineGrainRevert";
|
private fineGrainRevertBtn = "#fineGrainRevert";
|
||||||
|
|
||||||
private advancedTab = "#pf-tab-advanced-advanced";
|
private advancedTab = "advancedTab";
|
||||||
|
|
||||||
goToAdvancedTab() {
|
goToAdvancedTab() {
|
||||||
cy.get(this.advancedTab).click();
|
cy.findByTestId(this.advancedTab).click();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,11 +5,11 @@ import type ScopeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/s
|
||||||
type PermissionType = "resource" | "scope";
|
type PermissionType = "resource" | "scope";
|
||||||
|
|
||||||
export default class AuthorizationTab {
|
export default class AuthorizationTab {
|
||||||
private tabName = "#pf-tab-authorization-authorization";
|
private tabName = "authorizationTab";
|
||||||
private resourcesTabName = "#pf-tab-41-resources";
|
private resourcesTabName = "authorizationResources";
|
||||||
private scopeTabName = "#pf-tab-42-scopes";
|
private scopeTabName = "authorizationScopes";
|
||||||
private policyTabName = "#pf-tab-43-policies";
|
private policyTabName = "authorizationPolicies";
|
||||||
private permissionsTabName = "#pf-tab-44-permissions";
|
private permissionsTabName = "authorizationPermissions";
|
||||||
private nameColumnPrefix = "name-column-";
|
private nameColumnPrefix = "name-column-";
|
||||||
private emptyPolicyCreateButton = "no-policies-empty-action";
|
private emptyPolicyCreateButton = "no-policies-empty-action";
|
||||||
private createPolicyButton = "createPolicy";
|
private createPolicyButton = "createPolicy";
|
||||||
|
@ -19,27 +19,27 @@ export default class AuthorizationTab {
|
||||||
private permissionResourceDropdown = "#resources";
|
private permissionResourceDropdown = "#resources";
|
||||||
|
|
||||||
goToAuthenticationTab() {
|
goToAuthenticationTab() {
|
||||||
cy.get(this.tabName).click();
|
cy.findByTestId(this.tabName).click();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
goToResourceSubTab() {
|
goToResourceSubTab() {
|
||||||
cy.get(this.resourcesTabName).click();
|
cy.findByTestId(this.resourcesTabName).click();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
goToScopeSubTab() {
|
goToScopeSubTab() {
|
||||||
cy.get(this.scopeTabName).click();
|
cy.findByTestId(this.scopeTabName).click();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
goToPolicySubTab() {
|
goToPolicySubTab() {
|
||||||
cy.get(this.policyTabName).click();
|
cy.findByTestId(this.policyTabName).click();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
goToPermissionsSubTab() {
|
goToPermissionsSubTab() {
|
||||||
cy.get(this.permissionsTabName).click();
|
cy.findByTestId(this.permissionsTabName).click();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
export default class ClientScopesTab {
|
export default class ClientScopesTab {
|
||||||
private clientScopesTab = "#pf-tab-clientScopes-clientScopes";
|
private clientScopesTab = "clientScopesTab";
|
||||||
|
|
||||||
goToClientScopesTab() {
|
goToClientScopesTab() {
|
||||||
cy.get(this.clientScopesTab).click();
|
cy.findByTestId(this.clientScopesTab).click();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
export default class KeysTab {
|
export default class KeysTab {
|
||||||
private tabName = "#pf-tab-keys-keys";
|
private tabName = "keysTab";
|
||||||
private useJwksUrl = "useJwksUrl";
|
private useJwksUrl = "useJwksUrl";
|
||||||
private saveKeys = "saveKeys";
|
private saveKeys = "saveKeys";
|
||||||
private generate = "generate";
|
private generate = "generate";
|
||||||
|
@ -9,7 +9,7 @@ export default class KeysTab {
|
||||||
private confirm = "confirm";
|
private confirm = "confirm";
|
||||||
|
|
||||||
goToTab() {
|
goToTab() {
|
||||||
cy.get(this.tabName).click();
|
cy.findByTestId(this.tabName).click();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@ import {
|
||||||
Label,
|
Label,
|
||||||
PageSection,
|
PageSection,
|
||||||
Tab,
|
Tab,
|
||||||
Tabs,
|
|
||||||
TabTitleText,
|
TabTitleText,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
} from "@patternfly/react-core";
|
} from "@patternfly/react-core";
|
||||||
|
@ -24,7 +23,6 @@ import {
|
||||||
useConfirmDialog,
|
useConfirmDialog,
|
||||||
} from "../components/confirm-dialog/ConfirmDialog";
|
} from "../components/confirm-dialog/ConfirmDialog";
|
||||||
import { DownloadDialog } from "../components/download-dialog/DownloadDialog";
|
import { DownloadDialog } from "../components/download-dialog/DownloadDialog";
|
||||||
import { KeycloakTabs } from "../components/keycloak-tabs/KeycloakTabs";
|
|
||||||
import type { MultiLine } from "../components/multi-line-input/multi-line-convert";
|
import type { MultiLine } from "../components/multi-line-input/multi-line-convert";
|
||||||
import {
|
import {
|
||||||
ViewHeader,
|
ViewHeader,
|
||||||
|
@ -44,7 +42,7 @@ import { AdvancedTab } from "./AdvancedTab";
|
||||||
import { ClientSettings } from "./ClientSettings";
|
import { ClientSettings } from "./ClientSettings";
|
||||||
import { Credentials } from "./credentials/Credentials";
|
import { Credentials } from "./credentials/Credentials";
|
||||||
import { Keys } from "./keys/Keys";
|
import { Keys } from "./keys/Keys";
|
||||||
import type { ClientParams } from "./routes/Client";
|
import { ClientParams, ClientTab, toClient } from "./routes/Client";
|
||||||
import { toClients } from "./routes/Clients";
|
import { toClients } from "./routes/Clients";
|
||||||
import { ClientScopes } from "./scopes/ClientScopes";
|
import { ClientScopes } from "./scopes/ClientScopes";
|
||||||
import { EvaluateScopes } from "./scopes/EvaluateScopes";
|
import { EvaluateScopes } from "./scopes/EvaluateScopes";
|
||||||
|
@ -63,6 +61,15 @@ import { AuthorizationPermissions } from "./authorization/Permissions";
|
||||||
import { AuthorizationEvaluate } from "./authorization/AuthorizationEvaluate";
|
import { AuthorizationEvaluate } from "./authorization/AuthorizationEvaluate";
|
||||||
import type UserRepresentation from "@keycloak/keycloak-admin-client/lib/defs/userRepresentation";
|
import type UserRepresentation from "@keycloak/keycloak-admin-client/lib/defs/userRepresentation";
|
||||||
import type RoleRepresentation from "@keycloak/keycloak-admin-client/lib/defs/roleRepresentation";
|
import type RoleRepresentation from "@keycloak/keycloak-admin-client/lib/defs/roleRepresentation";
|
||||||
|
import {
|
||||||
|
routableTab,
|
||||||
|
RoutableTabs,
|
||||||
|
} from "../components/routable-tabs/RoutableTabs";
|
||||||
|
import {
|
||||||
|
AuthorizationTab,
|
||||||
|
toAuthorizationTab,
|
||||||
|
} from "./routes/AuthenticationTab";
|
||||||
|
import { toClientScopesTab } from "./routes/ClientScopeTab";
|
||||||
|
|
||||||
type ClientDetailHeaderProps = {
|
type ClientDetailHeaderProps = {
|
||||||
onChange: (value: boolean) => void;
|
onChange: (value: boolean) => void;
|
||||||
|
@ -185,8 +192,6 @@ export default function ClientDetails() {
|
||||||
|
|
||||||
const [downloadDialogOpen, toggleDownloadDialogOpen] = useToggle();
|
const [downloadDialogOpen, toggleDownloadDialogOpen] = useToggle();
|
||||||
const [changeAuthenticatorOpen, toggleChangeAuthenticatorOpen] = useToggle();
|
const [changeAuthenticatorOpen, toggleChangeAuthenticatorOpen] = useToggle();
|
||||||
const [clientScopeSubTab, setClientScopeSubTab] = useState(30);
|
|
||||||
const [authorizationSubTab, setAuthorizationSubTab] = useState(40);
|
|
||||||
|
|
||||||
const form = useForm<ClientForm>({ shouldUnregister: false });
|
const form = useForm<ClientForm>({ shouldUnregister: false });
|
||||||
const { clientId } = useParams<ClientParams>();
|
const { clientId } = useParams<ClientParams>();
|
||||||
|
@ -341,6 +346,26 @@ export default function ClientDetails() {
|
||||||
return <KeycloakSpinner />;
|
return <KeycloakSpinner />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const route = (tab: ClientTab) =>
|
||||||
|
routableTab({
|
||||||
|
to: toClient({
|
||||||
|
realm,
|
||||||
|
clientId,
|
||||||
|
tab,
|
||||||
|
}),
|
||||||
|
history,
|
||||||
|
});
|
||||||
|
|
||||||
|
const authenticationRoute = (tab: AuthorizationTab) =>
|
||||||
|
routableTab({
|
||||||
|
to: toAuthorizationTab({
|
||||||
|
realm,
|
||||||
|
clientId,
|
||||||
|
tab,
|
||||||
|
}),
|
||||||
|
history,
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ConfirmDialogModal
|
<ConfirmDialogModal
|
||||||
|
@ -385,11 +410,12 @@ export default function ClientDetails() {
|
||||||
/>
|
/>
|
||||||
<PageSection variant="light" className="pf-u-p-0">
|
<PageSection variant="light" className="pf-u-p-0">
|
||||||
<FormProvider {...form}>
|
<FormProvider {...form}>
|
||||||
<KeycloakTabs data-testid="client-tabs" isBox mountOnEnter>
|
<RoutableTabs data-testid="client-tabs" isBox mountOnEnter>
|
||||||
<Tab
|
<Tab
|
||||||
id="settings"
|
id="settings"
|
||||||
eventKey="settings"
|
data-testid="clientSettingsTab"
|
||||||
title={<TabTitleText>{t("common:settings")}</TabTitleText>}
|
title={<TabTitleText>{t("common:settings")}</TabTitleText>}
|
||||||
|
{...route("settings")}
|
||||||
>
|
>
|
||||||
<ClientSettings
|
<ClientSettings
|
||||||
client={client}
|
client={client}
|
||||||
|
@ -401,8 +427,9 @@ export default function ClientDetails() {
|
||||||
client.protocol === "saml") && (
|
client.protocol === "saml") && (
|
||||||
<Tab
|
<Tab
|
||||||
id="keys"
|
id="keys"
|
||||||
eventKey="keys"
|
data-testid="keysTab"
|
||||||
title={<TabTitleText>{t("keys")}</TabTitleText>}
|
title={<TabTitleText>{t("keys")}</TabTitleText>}
|
||||||
|
{...route("keys")}
|
||||||
>
|
>
|
||||||
{client.protocol === "openid-connect" && (
|
{client.protocol === "openid-connect" && (
|
||||||
<Keys clientId={clientId} save={save} />
|
<Keys clientId={clientId} save={save} />
|
||||||
|
@ -415,8 +442,8 @@ export default function ClientDetails() {
|
||||||
{!client.publicClient && !isRealmClient(client) && (
|
{!client.publicClient && !isRealmClient(client) && (
|
||||||
<Tab
|
<Tab
|
||||||
id="credentials"
|
id="credentials"
|
||||||
eventKey="credentials"
|
|
||||||
title={<TabTitleText>{t("credentials")}</TabTitleText>}
|
title={<TabTitleText>{t("credentials")}</TabTitleText>}
|
||||||
|
{...route("credentials")}
|
||||||
>
|
>
|
||||||
<Credentials clientId={clientId} save={() => save()} />
|
<Credentials clientId={clientId} save={() => save()} />
|
||||||
</Tab>
|
</Tab>
|
||||||
|
@ -424,8 +451,9 @@ export default function ClientDetails() {
|
||||||
{!isRealmClient(client) && (
|
{!isRealmClient(client) && (
|
||||||
<Tab
|
<Tab
|
||||||
id="mappers"
|
id="mappers"
|
||||||
eventKey="mappers"
|
data-testid="mappersTab"
|
||||||
title={<TabTitleText>{t("mappers")}</TabTitleText>}
|
title={<TabTitleText>{t("mappers")}</TabTitleText>}
|
||||||
|
{...route("mappers")}
|
||||||
>
|
>
|
||||||
<MapperList
|
<MapperList
|
||||||
model={client}
|
model={client}
|
||||||
|
@ -439,8 +467,9 @@ export default function ClientDetails() {
|
||||||
)}
|
)}
|
||||||
<Tab
|
<Tab
|
||||||
id="roles"
|
id="roles"
|
||||||
eventKey="roles"
|
data-testid="rolesTab"
|
||||||
title={<TabTitleText>{t("roles")}</TabTitleText>}
|
title={<TabTitleText>{t("roles")}</TabTitleText>}
|
||||||
|
{...route("roles")}
|
||||||
>
|
>
|
||||||
<RolesList
|
<RolesList
|
||||||
loader={loader}
|
loader={loader}
|
||||||
|
@ -451,17 +480,28 @@ export default function ClientDetails() {
|
||||||
{!isRealmClient(client) && (
|
{!isRealmClient(client) && (
|
||||||
<Tab
|
<Tab
|
||||||
id="clientScopes"
|
id="clientScopes"
|
||||||
eventKey="clientScopes"
|
data-testid="clientScopesTab"
|
||||||
title={<TabTitleText>{t("clientScopes")}</TabTitleText>}
|
title={<TabTitleText>{t("clientScopes")}</TabTitleText>}
|
||||||
|
{...route("clientScopes")}
|
||||||
>
|
>
|
||||||
<Tabs
|
<RoutableTabs
|
||||||
activeKey={clientScopeSubTab}
|
defaultLocation={toClientScopesTab({
|
||||||
onSelect={(_, key) => setClientScopeSubTab(key as number)}
|
realm,
|
||||||
|
clientId,
|
||||||
|
tab: "setup",
|
||||||
|
})}
|
||||||
>
|
>
|
||||||
<Tab
|
<Tab
|
||||||
id="setup"
|
id="setup"
|
||||||
eventKey={30}
|
|
||||||
title={<TabTitleText>{t("setup")}</TabTitleText>}
|
title={<TabTitleText>{t("setup")}</TabTitleText>}
|
||||||
|
{...routableTab({
|
||||||
|
to: toClientScopesTab({
|
||||||
|
realm,
|
||||||
|
clientId,
|
||||||
|
tab: "setup",
|
||||||
|
}),
|
||||||
|
history,
|
||||||
|
})}
|
||||||
>
|
>
|
||||||
<ClientScopes
|
<ClientScopes
|
||||||
clientName={client.clientId!}
|
clientName={client.clientId!}
|
||||||
|
@ -471,68 +511,85 @@ export default function ClientDetails() {
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab
|
<Tab
|
||||||
id="evaluate"
|
id="evaluate"
|
||||||
eventKey={31}
|
|
||||||
title={<TabTitleText>{t("evaluate")}</TabTitleText>}
|
title={<TabTitleText>{t("evaluate")}</TabTitleText>}
|
||||||
|
{...routableTab({
|
||||||
|
to: toClientScopesTab({
|
||||||
|
realm,
|
||||||
|
clientId,
|
||||||
|
tab: "evaluate",
|
||||||
|
}),
|
||||||
|
history,
|
||||||
|
})}
|
||||||
>
|
>
|
||||||
<EvaluateScopes
|
<EvaluateScopes
|
||||||
clientId={clientId}
|
clientId={clientId}
|
||||||
protocol={client!.protocol!}
|
protocol={client!.protocol!}
|
||||||
/>
|
/>
|
||||||
</Tab>
|
</Tab>
|
||||||
</Tabs>
|
</RoutableTabs>
|
||||||
</Tab>
|
</Tab>
|
||||||
)}
|
)}
|
||||||
{client!.serviceAccountsEnabled && (
|
{client!.serviceAccountsEnabled && (
|
||||||
<Tab
|
<Tab
|
||||||
id="authorization"
|
id="authorization"
|
||||||
eventKey="authorization"
|
data-testid="authorizationTab"
|
||||||
title={<TabTitleText>{t("authorization")}</TabTitleText>}
|
title={<TabTitleText>{t("authorization")}</TabTitleText>}
|
||||||
|
{...route("authorization")}
|
||||||
>
|
>
|
||||||
<Tabs
|
<RoutableTabs
|
||||||
activeKey={authorizationSubTab}
|
|
||||||
onSelect={(_, key) => setAuthorizationSubTab(key as number)}
|
|
||||||
mountOnEnter
|
mountOnEnter
|
||||||
unmountOnExit
|
unmountOnExit
|
||||||
|
defaultLocation={toAuthorizationTab({
|
||||||
|
realm,
|
||||||
|
clientId,
|
||||||
|
tab: "settings",
|
||||||
|
})}
|
||||||
>
|
>
|
||||||
<Tab
|
<Tab
|
||||||
id="settings"
|
id="settings"
|
||||||
eventKey={40}
|
data-testid="authorizationSettings"
|
||||||
title={<TabTitleText>{t("settings")}</TabTitleText>}
|
title={<TabTitleText>{t("settings")}</TabTitleText>}
|
||||||
|
{...authenticationRoute("settings")}
|
||||||
>
|
>
|
||||||
<AuthorizationSettings clientId={clientId} />
|
<AuthorizationSettings clientId={clientId} />
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab
|
<Tab
|
||||||
id="resources"
|
id="resources"
|
||||||
eventKey={41}
|
data-testid="authorizationResources"
|
||||||
title={<TabTitleText>{t("resources")}</TabTitleText>}
|
title={<TabTitleText>{t("resources")}</TabTitleText>}
|
||||||
|
{...authenticationRoute("resources")}
|
||||||
>
|
>
|
||||||
<AuthorizationResources clientId={clientId} />
|
<AuthorizationResources clientId={clientId} />
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab
|
<Tab
|
||||||
id="scopes"
|
id="scopes"
|
||||||
eventKey={42}
|
data-testid="authorizationScopes"
|
||||||
title={<TabTitleText>{t("scopes")}</TabTitleText>}
|
title={<TabTitleText>{t("scopes")}</TabTitleText>}
|
||||||
|
{...authenticationRoute("scopes")}
|
||||||
>
|
>
|
||||||
<AuthorizationScopes clientId={clientId} />
|
<AuthorizationScopes clientId={clientId} />
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab
|
<Tab
|
||||||
id="policies"
|
id="policies"
|
||||||
eventKey={43}
|
data-testid="authorizationPolicies"
|
||||||
title={<TabTitleText>{t("policies")}</TabTitleText>}
|
title={<TabTitleText>{t("policies")}</TabTitleText>}
|
||||||
|
{...authenticationRoute("policies")}
|
||||||
>
|
>
|
||||||
<AuthorizationPolicies clientId={clientId} />
|
<AuthorizationPolicies clientId={clientId} />
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab
|
<Tab
|
||||||
id="permissions"
|
id="permissions"
|
||||||
eventKey={44}
|
data-testid="authorizationPermissions"
|
||||||
title={<TabTitleText>{t("permissions")}</TabTitleText>}
|
title={<TabTitleText>{t("permissions")}</TabTitleText>}
|
||||||
|
{...authenticationRoute("permissions")}
|
||||||
>
|
>
|
||||||
<AuthorizationPermissions clientId={clientId} />
|
<AuthorizationPermissions clientId={clientId} />
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab
|
<Tab
|
||||||
id="Evaluate"
|
id="Evaluate"
|
||||||
eventKey={44}
|
data-testid="authorizationEvaluate"
|
||||||
title={<TabTitleText>{t("evaluate")}</TabTitleText>}
|
title={<TabTitleText>{t("evaluate")}</TabTitleText>}
|
||||||
|
{...authenticationRoute("evaluate")}
|
||||||
>
|
>
|
||||||
<AuthorizationEvaluate
|
<AuthorizationEvaluate
|
||||||
clients={clients}
|
clients={clients}
|
||||||
|
@ -543,26 +600,28 @@ export default function ClientDetails() {
|
||||||
reset={() => setupForm(client)}
|
reset={() => setupForm(client)}
|
||||||
/>
|
/>
|
||||||
</Tab>
|
</Tab>
|
||||||
</Tabs>
|
</RoutableTabs>
|
||||||
</Tab>
|
</Tab>
|
||||||
)}
|
)}
|
||||||
{client!.serviceAccountsEnabled && (
|
{client!.serviceAccountsEnabled && (
|
||||||
<Tab
|
<Tab
|
||||||
id="serviceAccount"
|
id="serviceAccount"
|
||||||
eventKey="serviceAccount"
|
data-testid="serviceAccountTab"
|
||||||
title={<TabTitleText>{t("serviceAccount")}</TabTitleText>}
|
title={<TabTitleText>{t("serviceAccount")}</TabTitleText>}
|
||||||
|
{...route("serviceAccount")}
|
||||||
>
|
>
|
||||||
<ServiceAccount client={client} />
|
<ServiceAccount client={client} />
|
||||||
</Tab>
|
</Tab>
|
||||||
)}
|
)}
|
||||||
<Tab
|
<Tab
|
||||||
id="advanced"
|
id="advanced"
|
||||||
eventKey="advanced"
|
data-testid="advancedTab"
|
||||||
title={<TabTitleText>{t("advanced")}</TabTitleText>}
|
title={<TabTitleText>{t("advanced")}</TabTitleText>}
|
||||||
|
{...route("advanced")}
|
||||||
>
|
>
|
||||||
<AdvancedTab save={save} client={client} />
|
<AdvancedTab save={save} client={client} />
|
||||||
</Tab>
|
</Tab>
|
||||||
</KeycloakTabs>
|
</RoutableTabs>
|
||||||
</FormProvider>
|
</FormProvider>
|
||||||
</PageSection>
|
</PageSection>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -27,9 +27,9 @@ import { useConfirmDialog } from "../../components/confirm-dialog/ConfirmDialog"
|
||||||
import { ViewHeader } from "../../components/view-header/ViewHeader";
|
import { ViewHeader } from "../../components/view-header/ViewHeader";
|
||||||
import { FormAccess } from "../../components/form-access/FormAccess";
|
import { FormAccess } from "../../components/form-access/FormAccess";
|
||||||
import { useAlerts } from "../../components/alert/Alerts";
|
import { useAlerts } from "../../components/alert/Alerts";
|
||||||
import { toClient } from "../routes/Client";
|
|
||||||
import { HelpItem } from "../../components/help-enabler/HelpItem";
|
import { HelpItem } from "../../components/help-enabler/HelpItem";
|
||||||
import { ResourcesPolicySelect } from "./ResourcesPolicySelect";
|
import { ResourcesPolicySelect } from "./ResourcesPolicySelect";
|
||||||
|
import { toAuthorizationTab } from "../routes/AuthenticationTab";
|
||||||
|
|
||||||
const DECISION_STRATEGIES = ["UNANIMOUS", "AFFIRMATIVE", "CONSENSUS"] as const;
|
const DECISION_STRATEGIES = ["UNANIMOUS", "AFFIRMATIVE", "CONSENSUS"] as const;
|
||||||
|
|
||||||
|
@ -140,7 +140,9 @@ export default function PermissionDetails() {
|
||||||
permissionId: permissionId,
|
permissionId: permissionId,
|
||||||
});
|
});
|
||||||
addAlert(t("permissionDeletedSuccess"), AlertVariant.success);
|
addAlert(t("permissionDeletedSuccess"), AlertVariant.success);
|
||||||
history.push(toClient({ realm, clientId: id, tab: "authorization" }));
|
history.push(
|
||||||
|
toAuthorizationTab({ realm, clientId: id, tab: "permissions" })
|
||||||
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
addError("clients:permissionDeletedError", error);
|
addError("clients:permissionDeletedError", error);
|
||||||
}
|
}
|
||||||
|
@ -329,10 +331,10 @@ export default function PermissionDetails() {
|
||||||
component={(props) => (
|
component={(props) => (
|
||||||
<Link
|
<Link
|
||||||
{...props}
|
{...props}
|
||||||
to={toClient({
|
to={toAuthorizationTab({
|
||||||
realm,
|
realm,
|
||||||
clientId: id,
|
clientId: id,
|
||||||
tab: "authorization",
|
tab: "permissions",
|
||||||
})}
|
})}
|
||||||
></Link>
|
></Link>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -31,7 +31,7 @@ import type { MultiLine } from "../../components/multi-line-input/multi-line-con
|
||||||
import type { KeyValueType } from "../../components/attribute-form/attribute-convert";
|
import type { KeyValueType } from "../../components/attribute-form/attribute-convert";
|
||||||
import { convertFormValuesToObject, convertToFormValues } from "../../util";
|
import { convertFormValuesToObject, convertToFormValues } from "../../util";
|
||||||
import { MultiLineInput } from "../../components/multi-line-input/MultiLineInput";
|
import { MultiLineInput } from "../../components/multi-line-input/MultiLineInput";
|
||||||
import { toClient } from "../routes/Client";
|
import { toAuthorizationTab } from "../routes/AuthenticationTab";
|
||||||
import { ScopePicker } from "./ScopePicker";
|
import { ScopePicker } from "./ScopePicker";
|
||||||
import { AttributeInput } from "../../components/attribute-input/AttributeInput";
|
import { AttributeInput } from "../../components/attribute-input/AttributeInput";
|
||||||
|
|
||||||
|
@ -142,7 +142,9 @@ export default function ResourceDetails() {
|
||||||
resourceId: resourceId!,
|
resourceId: resourceId!,
|
||||||
});
|
});
|
||||||
addAlert(t("resourceDeletedSuccess"), AlertVariant.success);
|
addAlert(t("resourceDeletedSuccess"), AlertVariant.success);
|
||||||
history.push(toClient({ realm, clientId: id, tab: "authorization" }));
|
history.push(
|
||||||
|
toAuthorizationTab({ realm, clientId: id, tab: "resources" })
|
||||||
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
addError("clients:resourceDeletedError", error);
|
addError("clients:resourceDeletedError", error);
|
||||||
}
|
}
|
||||||
|
@ -324,10 +326,10 @@ export default function ResourceDetails() {
|
||||||
component={(props) => (
|
component={(props) => (
|
||||||
<Link
|
<Link
|
||||||
{...props}
|
{...props}
|
||||||
to={toClient({
|
to={toAuthorizationTab({
|
||||||
realm,
|
realm,
|
||||||
clientId: id,
|
clientId: id,
|
||||||
tab: "authorization",
|
tab: "resources",
|
||||||
})}
|
})}
|
||||||
></Link>
|
></Link>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -19,7 +19,7 @@ import type { ScopeDetailsParams } from "../routes/Scope";
|
||||||
import { FormAccess } from "../../components/form-access/FormAccess";
|
import { FormAccess } from "../../components/form-access/FormAccess";
|
||||||
import { HelpItem } from "../../components/help-enabler/HelpItem";
|
import { HelpItem } from "../../components/help-enabler/HelpItem";
|
||||||
import { ViewHeader } from "../../components/view-header/ViewHeader";
|
import { ViewHeader } from "../../components/view-header/ViewHeader";
|
||||||
import { toClient } from "../routes/Client";
|
import { toAuthorizationTab } from "../routes/AuthenticationTab";
|
||||||
import { useAdminClient, useFetch } from "../../context/auth/AdminClient";
|
import { useAdminClient, useFetch } from "../../context/auth/AdminClient";
|
||||||
import { useAlerts } from "../../components/alert/Alerts";
|
import { useAlerts } from "../../components/alert/Alerts";
|
||||||
import useToggle from "../../utils/useToggle";
|
import useToggle from "../../utils/useToggle";
|
||||||
|
@ -77,7 +77,9 @@ export default function ScopeDetails() {
|
||||||
iconUri: scope.iconUri,
|
iconUri: scope.iconUri,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
history.push(toClient({ realm, clientId: id, tab: "authorization" }));
|
history.push(
|
||||||
|
toAuthorizationTab({ realm, clientId: id, tab: "scopes" })
|
||||||
|
);
|
||||||
}
|
}
|
||||||
addAlert(
|
addAlert(
|
||||||
t((scopeId ? "update" : "create") + "ScopeSuccess"),
|
t((scopeId ? "update" : "create") + "ScopeSuccess"),
|
||||||
|
@ -96,7 +98,9 @@ export default function ScopeDetails() {
|
||||||
toggleDialog={toggleDeleteDialog}
|
toggleDialog={toggleDeleteDialog}
|
||||||
selectedScope={scope}
|
selectedScope={scope}
|
||||||
refresh={() =>
|
refresh={() =>
|
||||||
history.push(toClient({ realm, clientId: id, tab: "authorization" }))
|
history.push(
|
||||||
|
toAuthorizationTab({ realm, clientId: id, tab: "scopes" })
|
||||||
|
)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<ViewHeader
|
<ViewHeader
|
||||||
|
@ -183,10 +187,10 @@ export default function ScopeDetails() {
|
||||||
component={(props) => (
|
component={(props) => (
|
||||||
<Link
|
<Link
|
||||||
{...props}
|
{...props}
|
||||||
to={toClient({
|
to={toAuthorizationTab({
|
||||||
realm,
|
realm,
|
||||||
clientId: id,
|
clientId: id,
|
||||||
tab: "authorization",
|
tab: "scopes",
|
||||||
})}
|
})}
|
||||||
></Link>
|
></Link>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -22,7 +22,7 @@ import { useConfirmDialog } from "../../../components/confirm-dialog/ConfirmDial
|
||||||
import { useAdminClient, useFetch } from "../../../context/auth/AdminClient";
|
import { useAdminClient, useFetch } from "../../../context/auth/AdminClient";
|
||||||
import { FormAccess } from "../../../components/form-access/FormAccess";
|
import { FormAccess } from "../../../components/form-access/FormAccess";
|
||||||
import { useAlerts } from "../../../components/alert/Alerts";
|
import { useAlerts } from "../../../components/alert/Alerts";
|
||||||
import { toClient } from "../../routes/Client";
|
import { toAuthorizationTab } from "../../routes/AuthenticationTab";
|
||||||
import { Aggregate } from "./Aggregate";
|
import { Aggregate } from "./Aggregate";
|
||||||
import { Client } from "./Client";
|
import { Client } from "./Client";
|
||||||
import { User } from "./User";
|
import { User } from "./User";
|
||||||
|
@ -150,7 +150,9 @@ export default function PolicyDetails() {
|
||||||
policyId,
|
policyId,
|
||||||
});
|
});
|
||||||
addAlert(t("policyDeletedSuccess"), AlertVariant.success);
|
addAlert(t("policyDeletedSuccess"), AlertVariant.success);
|
||||||
history.push(toClient({ realm, clientId: id, tab: "authorization" }));
|
history.push(
|
||||||
|
toAuthorizationTab({ realm, clientId: id, tab: "policies" })
|
||||||
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
addError("clients:policyDeletedError", error);
|
addError("clients:policyDeletedError", error);
|
||||||
}
|
}
|
||||||
|
@ -212,10 +214,10 @@ export default function PolicyDetails() {
|
||||||
component={(props) => (
|
component={(props) => (
|
||||||
<Link
|
<Link
|
||||||
{...props}
|
{...props}
|
||||||
to={toClient({
|
to={toAuthorizationTab({
|
||||||
realm,
|
realm,
|
||||||
clientId: id,
|
clientId: id,
|
||||||
tab: "authorization",
|
tab: "policies",
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -5,6 +5,8 @@ import { ClientsRoute } from "./routes/Clients";
|
||||||
import { CreateInitialAccessTokenRoute } from "./routes/CreateInitialAccessToken";
|
import { CreateInitialAccessTokenRoute } from "./routes/CreateInitialAccessToken";
|
||||||
import { ImportClientRoute } from "./routes/ImportClient";
|
import { ImportClientRoute } from "./routes/ImportClient";
|
||||||
import { MapperRoute } from "./routes/Mapper";
|
import { MapperRoute } from "./routes/Mapper";
|
||||||
|
import { ClientScopesRoute } from "./routes/ClientScopeTab";
|
||||||
|
import { AuthorizationRoute } from "./routes/AuthenticationTab";
|
||||||
import { NewResourceRoute } from "./routes/NewResource";
|
import { NewResourceRoute } from "./routes/NewResource";
|
||||||
import { ResourceDetailsRoute } from "./routes/Resource";
|
import { ResourceDetailsRoute } from "./routes/Resource";
|
||||||
import { NewScopeRoute } from "./routes/NewScope";
|
import { NewScopeRoute } from "./routes/NewScope";
|
||||||
|
@ -21,6 +23,8 @@ const routes: RouteDef[] = [
|
||||||
CreateInitialAccessTokenRoute,
|
CreateInitialAccessTokenRoute,
|
||||||
ClientRoute,
|
ClientRoute,
|
||||||
MapperRoute,
|
MapperRoute,
|
||||||
|
ClientScopesRoute,
|
||||||
|
AuthorizationRoute,
|
||||||
NewResourceRoute,
|
NewResourceRoute,
|
||||||
ResourceDetailsRoute,
|
ResourceDetailsRoute,
|
||||||
NewScopeRoute,
|
NewScopeRoute,
|
||||||
|
|
30
src/clients/routes/AuthenticationTab.ts
Normal file
30
src/clients/routes/AuthenticationTab.ts
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import type { LocationDescriptorObject } from "history";
|
||||||
|
import { lazy } from "react";
|
||||||
|
import { generatePath } from "react-router-dom";
|
||||||
|
import type { RouteDef } from "../../route-config";
|
||||||
|
|
||||||
|
export type AuthorizationTab =
|
||||||
|
| "settings"
|
||||||
|
| "resources"
|
||||||
|
| "scopes"
|
||||||
|
| "policies"
|
||||||
|
| "permissions"
|
||||||
|
| "evaluate";
|
||||||
|
|
||||||
|
export type AuthorizationParams = {
|
||||||
|
realm: string;
|
||||||
|
clientId: string;
|
||||||
|
tab: AuthorizationTab;
|
||||||
|
};
|
||||||
|
export const AuthorizationRoute: RouteDef = {
|
||||||
|
path: "/:realm/clients/:clientId/authorization/:tab",
|
||||||
|
component: lazy(() => import("../ClientDetails")),
|
||||||
|
breadcrumb: (t) => t("clients:clientSettings"),
|
||||||
|
access: "view-clients",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const toAuthorizationTab = (
|
||||||
|
params: AuthorizationParams
|
||||||
|
): LocationDescriptorObject => ({
|
||||||
|
pathname: generatePath(AuthorizationRoute.path, params),
|
||||||
|
});
|
|
@ -5,11 +5,14 @@ import type { RouteDef } from "../../route-config";
|
||||||
|
|
||||||
export type ClientTab =
|
export type ClientTab =
|
||||||
| "settings"
|
| "settings"
|
||||||
|
| "keys"
|
||||||
|
| "credentials"
|
||||||
| "roles"
|
| "roles"
|
||||||
| "clientScopes"
|
| "clientScopes"
|
||||||
| "advanced"
|
| "advanced"
|
||||||
| "mappers"
|
| "mappers"
|
||||||
| "authorization";
|
| "authorization"
|
||||||
|
| "serviceAccount";
|
||||||
|
|
||||||
export type ClientParams = {
|
export type ClientParams = {
|
||||||
realm: string;
|
realm: string;
|
||||||
|
|
24
src/clients/routes/ClientScopeTab.ts
Normal file
24
src/clients/routes/ClientScopeTab.ts
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import type { LocationDescriptorObject } from "history";
|
||||||
|
import { lazy } from "react";
|
||||||
|
import { generatePath } from "react-router-dom";
|
||||||
|
import type { RouteDef } from "../../route-config";
|
||||||
|
|
||||||
|
export type ClientScopesTab = "setup" | "evaluate";
|
||||||
|
|
||||||
|
export type ClientScopesParams = {
|
||||||
|
realm: string;
|
||||||
|
clientId: string;
|
||||||
|
tab: ClientScopesTab;
|
||||||
|
};
|
||||||
|
export const ClientScopesRoute: RouteDef = {
|
||||||
|
path: "/:realm/clients/:clientId/clientScopes/:tab",
|
||||||
|
component: lazy(() => import("../ClientDetails")),
|
||||||
|
breadcrumb: (t) => t("clients:clientSettings"),
|
||||||
|
access: "view-clients",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const toClientScopesTab = (
|
||||||
|
params: ClientScopesParams
|
||||||
|
): LocationDescriptorObject => ({
|
||||||
|
pathname: generatePath(ClientScopesRoute.path, params),
|
||||||
|
});
|
Loading…
Reference in a new issue