diff --git a/cypress/integration/clients_test.spec.ts b/cypress/integration/clients_test.spec.ts
index 2b2898e51e..a6a66e8286 100644
--- a/cypress/integration/clients_test.spec.ts
+++ b/cypress/integration/clients_test.spec.ts
@@ -837,7 +837,7 @@ describe("Clients test", () => {
.checkTabExists(ClientsDetailsTab.Settings, true)
.checkTabExists(ClientsDetailsTab.Roles, true)
.checkTabExists(ClientsDetailsTab.Advanced, true)
- .checkNumberOfTabsIsEqual(3);
+ .checkNumberOfTabsIsEqual(4);
});
it("Hides the delete action", () => {
diff --git a/src/clients/ClientDetails.tsx b/src/clients/ClientDetails.tsx
index 8218df30d3..6dada13a30 100644
--- a/src/clients/ClientDetails.tsx
+++ b/src/clients/ClientDetails.tsx
@@ -69,6 +69,8 @@ import {
import { toClientScopesTab } from "./routes/ClientScopeTab";
import { AuthorizationExport } from "./authorization/AuthorizationExport";
import { arrayToAttributes } from "../components/attribute-form/attribute-convert";
+import { useServerInfo } from "../context/server-info/ServerInfoProvider";
+import { PermissionsTab } from "./permissions/PermissionTab";
type ClientDetailHeaderProps = {
onChange: (value: boolean) => void;
@@ -178,6 +180,7 @@ export default function ClientDetails() {
const adminClient = useAdminClient();
const { addAlert, addError } = useAlerts();
const { realm } = useRealm();
+ const { profileInfo } = useServerInfo();
const history = useHistory();
@@ -555,6 +558,19 @@ export default function ClientDetails() {
)}
+ {!profileInfo?.disabledFeatures?.includes(
+ "ADMIN_FINE_GRAINED_AUTHZ"
+ ) &&
+ client.access?.manage && (
+ {t("permissions")}}
+ {...route("permissions")}
+ >
+
+
+ )}
{
+ const { t } = useTranslation("clients");
+ const history = useHistory();
+ const adminClient = useAdminClient();
+ const { realm } = useRealm();
+ const [realmId, setRealmId] = useState("");
+ const [permission, setPermission] = useState();
+
+ useEffect(() => {
+ Promise.all([
+ adminClient.clients.find({
+ search: true,
+ clientId: realm,
+ }),
+ adminClient.clients.listFineGrainPermissions({ id: clientId }),
+ ]).then(([clients, permission]) => {
+ setRealmId(clients[0]?.id!);
+ setPermission(permission);
+ });
+ }, []);
+
+ const PermissionDetailLink = (permission: Record) => (
+
+ {permission.name}
+
+ );
+
+ if (!permission) {
+ return ;
+ }
+
+ return (
+
+
+
+
+ ({
+ id,
+ name,
+ })
+ )}
+ ariaLabelKey="clients:permissions"
+ searchPlaceholderKey="clients:searchForPermission"
+ actionResolver={(rowData: IRowData) => {
+ const permission: Record = rowData.data;
+ return [
+ {
+ title: t("common:edit"),
+ onClick() {
+ history.push(
+ toPermissionDetails({
+ realm,
+ id: realmId,
+ permissionType: "scope",
+ permissionId: permission.id,
+ })
+ );
+ },
+ },
+ ];
+ }}
+ columns={[
+ {
+ name: "scopeName",
+ displayKey: "common:name",
+ cellRenderer: PermissionDetailLink,
+ },
+ {
+ name: "description",
+ displayKey: "common:description",
+ cellRenderer: (permission: Record) =>
+ t(`scopePermissions.${permission.name}-description`),
+ },
+ ]}
+ />
+
+ );
+};
diff --git a/src/clients/permissions/permissions-tab.css b/src/clients/permissions/permissions-tab.css
new file mode 100644
index 0000000000..b9fbacc39c
--- /dev/null
+++ b/src/clients/permissions/permissions-tab.css
@@ -0,0 +1,4 @@
+
+.permission-label > .pf-c-form__group-label {
+ width: 120%;
+}
\ No newline at end of file
diff --git a/src/clients/routes/Client.ts b/src/clients/routes/Client.ts
index 5c72e38fac..b877fe7c69 100644
--- a/src/clients/routes/Client.ts
+++ b/src/clients/routes/Client.ts
@@ -12,7 +12,8 @@ export type ClientTab =
| "advanced"
| "mappers"
| "authorization"
- | "serviceAccount";
+ | "serviceAccount"
+ | "permissions";
export type ClientParams = {
realm: string;