keycloak-scim/js/apps/admin-ui/src/PageNav.tsx
Erik Jan de Wit f088b0009c
initial ui for organizations (#29643)
* initial screen

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* more screens

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* added members tab

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* added the backend

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* added member add / invite models

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* initial version of the identity provider section

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* add link and unlink providers

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* small fix

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* PR comments

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* Do not validate broker domain when the domain is an empty string

Closes #29759

Signed-off-by: Pedro Igor <pigor.craveiro@gmail.com>
Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* added filter and value

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* added test

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* added first name last name

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* refresh menu when realm organization is changed

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* changed to record

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* changed to form data

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* fixed lint error

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* Changing name of invitation parameters

Signed-off-by: Pedro Igor <pigor.craveiro@gmail.com>
Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* Chancing name of parameters on the client

Signed-off-by: Pedro Igor <pigor.craveiro@gmail.com>
Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* Enable organization at the realm before running tests

Signed-off-by: Pedro Igor <pigor.craveiro@gmail.com>
Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* Domain help message

Signed-off-by: Pedro Igor <pigor.craveiro@gmail.com>
Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* Handling model validation errors when creating organizations

Signed-off-by: Pedro Igor <pigor.craveiro@gmail.com>
Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* Message key for organizationDetails

Signed-off-by: Pedro Igor <pigor.craveiro@gmail.com>
Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* Do not change kc.org attribute on group

Signed-off-by: Pedro Igor <pigor.craveiro@gmail.com>
Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* add realm into the context

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* tests

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* Changing button in invitation model to use Send instead of Save

Signed-off-by: Pedro Igor <pigor.craveiro@gmail.com>
Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* Better message when validating the organization domain

Signed-off-by: Pedro Igor <pigor.craveiro@gmail.com>
Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* Fixing compilation error after rebase

Signed-off-by: Pedro Igor <pigor.craveiro@gmail.com>
Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* fixed test

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* removed wait as it no longer required and skip flacky test

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* skip tests that are flaky

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* stabilize user create test

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

---------

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>
Signed-off-by: Pedro Igor <pigor.craveiro@gmail.com>
Co-authored-by: Pedro Igor <pigor.craveiro@gmail.com>
2024-05-29 14:34:02 +02:00

146 lines
4.5 KiB
TypeScript

import {
Divider,
Nav,
NavGroup,
NavItem,
NavList,
PageSidebar,
PageSidebarBody,
} from "@patternfly/react-core";
import { FormEvent } from "react";
import { useTranslation } from "react-i18next";
import { NavLink, useMatch, useNavigate } from "react-router-dom";
import { RealmSelector } from "./components/realm-selector/RealmSelector";
import { useAccess } from "./context/access/Access";
import { useRealm } from "./context/realm-context/RealmContext";
import { useServerInfo } from "./context/server-info/ServerInfoProvider";
import { toPage } from "./page/routes";
import { AddRealmRoute } from "./realm/routes/AddRealm";
import { routes } from "./routes";
import useIsFeatureEnabled, { Feature } from "./utils/useIsFeatureEnabled";
import "./page-nav.css";
type LeftNavProps = { title: string; path: string; id?: string };
const LeftNav = ({ title, path, id }: LeftNavProps) => {
const { t } = useTranslation();
const { hasAccess } = useAccess();
const { realm } = useRealm();
const encodedRealm = encodeURIComponent(realm);
const route = routes.find(
(route) =>
route.path.replace(/\/:.+?(\?|(?:(?!\/).)*|$)/g, "") === (id || path),
);
const accessAllowed =
route &&
(route.handle.access instanceof Array
? hasAccess(...route.handle.access)
: hasAccess(route.handle.access));
if (!accessAllowed) {
return null;
}
return (
<li>
<NavLink
id={"nav-item" + path.replace("/", "-")}
to={`/${encodedRealm}${path}`}
className={({ isActive }) =>
`pf-v5-c-nav__link${isActive ? " pf-m-current" : ""}`
}
>
{t(title)}
</NavLink>
</li>
);
};
export const PageNav = () => {
const { t } = useTranslation();
const { hasSomeAccess } = useAccess();
const { componentTypes } = useServerInfo();
const isFeatureEnabled = useIsFeatureEnabled();
const pages =
componentTypes?.["org.keycloak.services.ui.extend.UiPageProvider"];
const navigate = useNavigate();
const { realmRepresentation } = useRealm();
type SelectedItem = {
groupId: number | string;
itemId: number | string;
to: string;
event: FormEvent<HTMLInputElement>;
};
const onSelect = (item: SelectedItem) => {
navigate(item.to);
item.event.preventDefault();
};
const showManage = hasSomeAccess(
"view-realm",
"query-groups",
"query-users",
"query-clients",
"view-events",
);
const showConfigure = hasSomeAccess(
"view-realm",
"query-clients",
"view-identity-providers",
);
const isOnAddRealm = !!useMatch(AddRealmRoute.path);
return (
<PageSidebar className="keycloak__page_nav__nav">
<PageSidebarBody>
<Nav onSelect={(_event, item) => onSelect(item as SelectedItem)}>
<NavList>
<NavItem className="keycloak__page_nav__nav_item__realm-selector">
<RealmSelector />
</NavItem>
</NavList>
<Divider />
{showManage && !isOnAddRealm && (
<NavGroup aria-label={t("manage")} title={t("manage")}>
{isFeatureEnabled(Feature.Organizations) &&
realmRepresentation?.organizationsEnabled && (
<LeftNav title="organizations" path="/organizations" />
)}
<LeftNav title="clients" path="/clients" />
<LeftNav title="clientScopes" path="/client-scopes" />
<LeftNav title="realmRoles" path="/roles" />
<LeftNav title="users" path="/users" />
<LeftNav title="groups" path="/groups" />
<LeftNav title="sessions" path="/sessions" />
<LeftNav title="events" path="/events" />
</NavGroup>
)}
{showConfigure && !isOnAddRealm && (
<NavGroup aria-label={t("configure")} title={t("configure")}>
<LeftNav title="realmSettings" path="/realm-settings" />
<LeftNav title="authentication" path="/authentication" />
<LeftNav title="identityProviders" path="/identity-providers" />
<LeftNav title="userFederation" path="/user-federation" />
{isFeatureEnabled(Feature.DeclarativeUI) &&
pages?.map((p) => (
<LeftNav
key={p.id}
title={p.id}
path={toPage({ providerId: p.id }).pathname!}
id="/page-section"
/>
))}
</NavGroup>
)}
</Nav>
</PageSidebarBody>
</PageSidebar>
);
};