diff --git a/apps/account-ui/public/locales/en/translation.json b/apps/account-ui/public/locales/en/translation.json
index 5db85fb805..bcdfaac96b 100644
--- a/apps/account-ui/public/locales/en/translation.json
+++ b/apps/account-ui/public/locales/en/translation.json
@@ -19,6 +19,7 @@
"description": "Description",
"device-activity": "Device activity",
"deviceActivity": "Device activity",
+ "directMembership": "Direct membership",
"doDeny": "Deny",
"done": "Done",
"doSignOut": "Sign out",
@@ -29,6 +30,8 @@
"filterByName": "Filter By Name ...",
"firstName": "First name",
"fullName": "{{givenName}} {{familyName}}",
+ "groupDescriptionLabel": "View groups that you are associated with",
+ "groupLabel": "Groups",
"groups": "Groups",
"infoMessage": "By clicking Remove Access, you will remove granted permissions of this application. This application will no longer use your information.",
"internalApp": "Internal",
@@ -47,6 +50,8 @@
"manageAccount": "Manage account",
"myResources": "My Resources",
"name": "Name",
+ "noGroups": "No groups",
+ "noGroupsText": "You are not joined in any group",
"notInUse": "Not in use",
"notSetUp": "{{0}} is not set up.",
"offlineAccess": "Offline access",
@@ -55,6 +60,7 @@
"password-display-name": "Password",
"password-help-text": "Sign in by entering your password.",
"password": "My password",
+ "path": "Path",
"permissionRequest": "Permission requests - {{0}}",
"permissionRequests": "Permission requests",
"permissions": "Permissions",
diff --git a/apps/account-ui/src/account-security/LinkedAccounts.tsx b/apps/account-ui/src/account-security/LinkedAccounts.tsx
index 379da42448..f13aec9320 100644
--- a/apps/account-ui/src/account-security/LinkedAccounts.tsx
+++ b/apps/account-ui/src/account-security/LinkedAccounts.tsx
@@ -1,15 +1,10 @@
-import {
- DataList,
- PageSection,
- Stack,
- StackItem,
- Title,
-} from "@patternfly/react-core";
+import { DataList, Stack, StackItem, Title } from "@patternfly/react-core";
import { useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { getLinkedAccounts } from "../api/methods";
import { LinkedAccountRepresentation } from "../api/representations";
import { EmptyRow } from "../components/datalist/EmptyRow";
+import { Page } from "../components/page/Page";
import { usePromise } from "../utils/usePromise";
import { AccountRow } from "./AccountRow";
@@ -33,7 +28,10 @@ const LinkedAccounts = () => {
);
return (
-
+
@@ -73,7 +71,7 @@ const LinkedAccounts = () => {
-
+
);
};
diff --git a/apps/account-ui/src/api/methods.ts b/apps/account-ui/src/api/methods.ts
index 9733725edd..b0ac4547a2 100644
--- a/apps/account-ui/src/api/methods.ts
+++ b/apps/account-ui/src/api/methods.ts
@@ -6,6 +6,7 @@ import {
CredentialContainer,
CredentialRepresentation,
DeviceRepresentation,
+ Group,
LinkedAccountRepresentation,
Permission,
UserRepresentation,
@@ -103,3 +104,10 @@ export async function linkAccount(account: LinkedAccountRepresentation) {
});
return parseResponse<{ accountLinkUri: string }>(response);
}
+
+export async function getGroups({ signal }: CallOptions) {
+ const response = await request("/groups", {
+ signal,
+ });
+ return parseResponse(response);
+}
diff --git a/apps/account-ui/src/api/representations.ts b/apps/account-ui/src/api/representations.ts
index 8a79605594..047e23d40e 100644
--- a/apps/account-ui/src/api/representations.ts
+++ b/apps/account-ui/src/api/representations.ts
@@ -202,3 +202,9 @@ export interface Permissions {
permissions: Permission[];
row?: number;
}
+
+export interface Group {
+ id?: string;
+ name: string;
+ path: string;
+}
diff --git a/apps/account-ui/src/groups/Groups.tsx b/apps/account-ui/src/groups/Groups.tsx
index a86b2ece3f..acddaecbfc 100644
--- a/apps/account-ui/src/groups/Groups.tsx
+++ b/apps/account-ui/src/groups/Groups.tsx
@@ -1,5 +1,133 @@
-import { PageSection } from "@patternfly/react-core";
+import {
+ Checkbox,
+ DataList,
+ DataListCell,
+ DataListItem,
+ DataListItemCells,
+ DataListItemRow,
+} from "@patternfly/react-core";
+import { useState } from "react";
+import { useTranslation } from "react-i18next";
+import { getGroups } from "../api/methods";
+import { Group } from "../api/representations";
+import { Page } from "../components/page/Page";
+import { usePromise } from "../utils/usePromise";
-const Groups = () => This is the groups page.;
+const Groups = () => {
+ const { t } = useTranslation();
+
+ const [groups, setGroups] = useState([]);
+ const [directMembership, setDirectMembership] = useState(false);
+
+ usePromise(
+ (signal) => getGroups({ signal }),
+ (groups) => {
+ if (directMembership) {
+ groups.forEach((el) =>
+ getParents(
+ el,
+ groups,
+ groups.map(({ path }) => path)
+ )
+ );
+ }
+ setGroups(groups);
+ },
+ [directMembership]
+ );
+
+ const getParents = (el: Group, groups: Group[], groupsPaths: string[]) => {
+ const parentPath = el.path.slice(0, el.path.lastIndexOf("/"));
+ if (parentPath && !groupsPaths.includes(parentPath)) {
+ el = {
+ name: parentPath.slice(parentPath.lastIndexOf("/") + 1),
+ path: parentPath,
+ };
+ groups.push(el);
+ groupsPaths.push(parentPath);
+
+ getParents(el, groups, groupsPaths);
+ }
+ };
+
+ return (
+
+
+
+ );
+};
export default Groups;