diff --git a/cypress/integration/users_test.spec.ts b/cypress/integration/users_test.spec.ts
index 0ad74eaede..5f89dc7201 100644
--- a/cypress/integration/users_test.spec.ts
+++ b/cypress/integration/users_test.spec.ts
@@ -126,8 +126,19 @@ describe("Users test", () => {
cy.getId("modalConfirm").click();
});
- it("Delete user", function () {
+ it("Go to user consents test", function () {
+ cy.wait(1000);
listingPage.searchItem(itemId).itemExist(itemId);
+
+ cy.wait(1000);
+ listingPage.goToItemDetails(itemId);
+
+ cy.getId("user-consents-tab").click();
+
+ cy.getId("empty-state").contains("No consents");
+ });
+
+ it("Delete user test", function () {
// Delete
cy.wait(1000);
listingPage.deleteItem(itemId);
diff --git a/src/client-scopes/messages.json b/src/client-scopes/messages.json
index 8691815e0a..34d745383f 100644
--- a/src/client-scopes/messages.json
+++ b/src/client-scopes/messages.json
@@ -2,6 +2,7 @@
"client-scopes": {
"createClientScope": "Create client scope",
"clientScopeList": "Client scopes",
+ "grantedClientScopes": "Granted client scopes",
"clientScopeDetails": "Client scope details",
"clientScopeExplain": "Client scopes allow you to define a common set of protocol mappers and roles, which are shared between multiple clients",
"searchFor": "Search for client scope",
diff --git a/src/clients/ClientsSection.tsx b/src/clients/ClientsSection.tsx
index 7b0e808941..4f255f8ddf 100644
--- a/src/clients/ClientsSection.tsx
+++ b/src/clients/ClientsSection.tsx
@@ -99,6 +99,7 @@ export const ClientsSection = () => {
>}
loader={loader}
isPaginated
ariaLabelKey="clients:clientList"
diff --git a/src/clients/messages.json b/src/clients/messages.json
index 2a9c7d9fab..699d30912a 100644
--- a/src/clients/messages.json
+++ b/src/clients/messages.json
@@ -83,6 +83,8 @@
"tokenDeleteSuccess": "initial access token created successfully",
"tokenDeleteError": "Could not delete initial access token: '{{error}}'",
"timestamp": "Created date",
+ "created": "Created",
+ "lastUpdated": "Last updated",
"expires": "Expires",
"count": "Count",
"remainingCount": "Remaining count",
diff --git a/src/components/list-empty-state/ListEmptyState.tsx b/src/components/list-empty-state/ListEmptyState.tsx
index 6ffc94b407..fb4dbe4666 100644
--- a/src/components/list-empty-state/ListEmptyState.tsx
+++ b/src/components/list-empty-state/ListEmptyState.tsx
@@ -8,6 +8,7 @@ import {
ButtonVariant,
EmptyStateSecondaryActions,
} from "@patternfly/react-core";
+import { SVGIconProps } from "@patternfly/react-icons/dist/js/createIcon";
import { PlusCircleIcon } from "@patternfly/react-icons";
import { SearchIcon } from "@patternfly/react-icons";
@@ -23,6 +24,7 @@ export type ListEmptyStateProps = {
primaryActionText?: string;
onPrimaryAction?: MouseEventHandler;
hasIcon?: boolean;
+ icon?: React.ComponentClass;
isSearchVariant?: boolean;
secondaryActions?: Action[];
};
@@ -35,6 +37,7 @@ export const ListEmptyState = ({
isSearchVariant,
primaryActionText,
secondaryActions,
+ icon,
}: ListEmptyStateProps) => {
return (
<>
@@ -42,7 +45,7 @@ export const ListEmptyState = ({
{hasIcon && isSearchVariant ? (
) : (
- hasIcon &&
+ hasIcon &&
)}
{message}
diff --git a/src/components/table-toolbar/KeycloakDataTable.tsx b/src/components/table-toolbar/KeycloakDataTable.tsx
index 8ca1687202..fee52c73b2 100644
--- a/src/components/table-toolbar/KeycloakDataTable.tsx
+++ b/src/components/table-toolbar/KeycloakDataTable.tsx
@@ -18,6 +18,7 @@ import _ from "lodash";
import { PaginatingTableToolbar } from "./PaginatingTableToolbar";
import { asyncStateFetch } from "../../context/auth/AdminClient";
import { ListEmptyState } from "../list-empty-state/ListEmptyState";
+import { SVGIconProps } from "@patternfly/react-icons/dist/js/createIcon";
type Row = {
data: T;
@@ -98,6 +99,7 @@ export type DataListProps = {
searchTypeComponent?: ReactNode;
toolbarItem?: ReactNode;
emptyState?: ReactNode;
+ icon?: React.ComponentClass;
};
/**
@@ -136,6 +138,7 @@ export function KeycloakDataTable({
searchTypeComponent,
toolbarItem,
emptyState,
+ icon,
...props
}: DataListProps) {
const { t } = useTranslation();
@@ -330,6 +333,7 @@ export function KeycloakDataTable({
searchPlaceholderKey && (
{
+ const { t } = useTranslation("roles");
+
+ const adminClient = useAdminClient();
+ const { id } = useParams<{ id: string }>();
+ const alphabetize = (consentsList: UserConsentRepresentation[]) => {
+ return _.sortBy(consentsList, (client) => client.clientId?.toUpperCase());
+ };
+
+ const loader = async () => {
+ const consents = await adminClient.users.listConsents({ id });
+
+ return alphabetize(consents);
+ };
+
+ const clientScopesRenderer = ({
+ grantedClientScopes,
+ }: UserConsentRepresentation) => {
+ return <>{grantedClientScopes!.join(", ")}>;
+ };
+
+ const createdRenderer = ({ createDate }: UserConsentRepresentation) => {
+ return <>{moment(createDate).format("MM/DD/YY hh:MM A")}>;
+ };
+
+ const lastUpdatedRenderer = ({
+ lastUpdatedDate,
+ }: UserConsentRepresentation) => {
+ return <>{moment(lastUpdatedDate).format("MM/DD/YY hh:MM A")}>;
+ };
+
+ return (
+ <>
+
+ {}}
+ />
+ }
+ />
+
+ >
+ );
+};
diff --git a/src/user/UsersTabs.tsx b/src/user/UsersTabs.tsx
index 56935b3fbe..bb23e04b61 100644
--- a/src/user/UsersTabs.tsx
+++ b/src/user/UsersTabs.tsx
@@ -16,6 +16,7 @@ import { useAdminClient } from "../context/auth/AdminClient";
import { useHistory, useParams, useRouteMatch } from "react-router-dom";
import { KeycloakTabs } from "../components/keycloak-tabs/KeycloakTabs";
import { UserGroups } from "./UserGroups";
+import { UserConsents } from "./UserConsents";
export const UsersTabs = () => {
const { t } = useTranslation("roles");
@@ -24,7 +25,7 @@ export const UsersTabs = () => {
const history = useHistory();
const adminClient = useAdminClient();
- const form = useForm({ mode: "onChange" });
+ const userForm = useForm({ mode: "onChange" });
const { id } = useParams<{ id: string }>();
const [user, setUser] = useState("");
@@ -69,7 +70,7 @@ export const UsersTabs = () => {
data-testid="user-details-tab"
title={{t("details")}}
>
-
+
{
>
+ {t("users:consents")}}
+ >
+
+
)}
- {!id && }
+ {!id && }
>
);
diff --git a/src/user/messages.json b/src/user/messages.json
index 14c0ce5ca4..9269dac8c1 100644
--- a/src/user/messages.json
+++ b/src/user/messages.json
@@ -52,7 +52,11 @@
"updatePassword": "Update Password",
"updateProfile": "Update Profile",
"verifyEmail": "Verify Email",
- "updateUserLocale": "Update User Locale"
+ "updateUserLocale": "Update User Locale",
+ "consents": "Consents",
+ "noConsents": "No consents",
+ "noConsentsText": "The consents will only be recorded when users try to access a client that is configured to require consent. In that case, users will get a consent page which asks them to grant access to the client."
+
}
}