Repository: wso2/identity-apps
Pull request #7929: Redesign user group assignment view to be consistent with other views
Author: login: DonOmalVindula
Created: 2025-03-20T12:08:32Z | Merged: 2025-03-24T04:28:36Z

<!-- Please fill in the pull request template when submitting pull requests. -->

### Purpose
<!-- Describe the problem, feature, improvement or the change introduces by the PR briefly. Add screenshots/GIFs if UI/UX changes are introduced. -->
$subject. The new UI would be as follows
<img width="1680" alt="Screenshot 2025-03-21 at 16 44 02" src="https://github.com/user-attachments/assets/73afa8e6-3786-4e3b-9622-5c0449aaebab" />

Existing (Old) UI
<img width="1680" alt="Screenshot 2025-03-21 at 16 49 35" src="https://github.com/user-attachments/assets/0868ca5f-f47e-4e45-ae91-ce8a7677c3d8" />


### Related Issues
<!-- Mention the issue/s related to the pull request. Make sure to only add publicly accessible references. -->
- N/A

### Related PRs
<!-- Mention the related pull requests. Make sure to only add publicly accessible references. -->
- N/A

### Checklist

- [ ] e2e cypress tests locally verified. (for internal contributers)
- [ ] Manual test round performed and verified.
- [ ] UX/UI review done on the final implementation.
- [ ] Documentation provided. (Add links if there are any)
- [ ] Relevant backend changes deployed and verified
- [ ] [Unit tests](/docs/testing/UNIT_TESTING.md) provided. (Add links if there are any)
- [ ] [Integration tests](https://github.com/wso2/product-is/tree/master/modules/integration) provided. (Add links if there are any)

### Security checks
- [ ] Followed secure coding standards in http://wso2.com/technical-reports/wso2-secure-engineering-guidelines
- [ ] Ran FindSecurityBugs plugin and verified report
- [ ] Confirmed that this PR doesn't commit any keys, passwords, tokens, usernames, or other secrets



Diff:
diff --git a/.changeset/popular-mails-joke.md b/.changeset/popular-mails-joke.md
new file mode 100644
index 00000000000..b58f49bc906
--- /dev/null
+++ b/.changeset/popular-mails-joke.md
@@ -0,0 +1,7 @@
+---
+"@wso2is/admin.users.v1": patch
+"@wso2is/i18n": patch
+"@wso2is/console": patch
+---
+
+Refactor user group assignment view to be consistent with other tabs
diff --git a/features/admin.users.v1/components/user-groups-edit.tsx b/features/admin.users.v1/components/user-groups-edit.tsx
index b647405b26c..8861788cf21 100644
--- a/features/admin.users.v1/components/user-groups-edit.tsx
+++ b/features/admin.users.v1/components/user-groups-edit.tsx
@@ -17,7 +17,6 @@
  */
 
 import { updateResources } from "@wso2is/admin.core.v1/api/bulk-operations";
-import { getEmptyPlaceholderIllustrations } from "@wso2is/admin.core.v1/configs/ui";
 import { AppState } from "@wso2is/admin.core.v1/store";
 import { userstoresConfig } from "@wso2is/admin.extensions.v1/configs/userstores";
 import { useGroupList } from "@wso2is/admin.groups.v1/api/groups";
@@ -27,15 +26,12 @@ import { PRIMARY_USERSTORE } from "@wso2is/admin.userstores.v1/constants";
 import {
     AlertInterface,
     AlertLevels,
-    ProfileInfoInterface,
-    RolesMemberInterface
+    ProfileInfoInterface
 } from "@wso2is/core/models";
 import { addAlert } from "@wso2is/core/store";
 import { StringUtils } from "@wso2is/core/utils";
 import {
     ContentLoader,
-    EmphasizedSegment,
-    EmptyPlaceholder,
     Heading,
     ItemTypeLabelPropsInterface,
     LinkButton,
@@ -48,20 +44,15 @@ import { AxiosError, AxiosRequestConfig } from "axios";
 import escapeRegExp from "lodash-es/escapeRegExp";
 import forEachRight from "lodash-es/forEachRight";
 import isEmpty from "lodash-es/isEmpty";
-import React, { ChangeEvent, FormEvent, FunctionComponent, ReactElement, useEffect, useMemo, useState } from "react";
+import React, { FormEvent, FunctionComponent, ReactElement, useEffect, useMemo, useState } from "react";
 import { useTranslation } from "react-i18next";
 import { useDispatch, useSelector } from "react-redux";
 import { Dispatch } from "redux";
 import {
-    Button,
-    Divider,
     Grid,
-    Icon,
-    Input,
-    Label,
-    Modal,
-    Table
+    Modal
 } from "semantic-ui-react";
+import { UserGroupsListTable } from "./user-groups-list";
 
 interface UserGroupsPropsInterface {
     /**
@@ -106,7 +97,6 @@ export const UserGroupsList: FunctionComponent<UserGroupsPropsInterface> = (
     const [ initialGroupList, setInitialGroupList ] = useState([]);
     const [ primaryGroupsList, setPrimaryGroupsList ] = useState<Map<string, string>>(undefined);
     const [ isSelectAllGroupsChecked, setIsSelectAllGroupsChecked ] = useState(false);
-    const [ assignedGroups, setAssignedGroups ] = useState<RolesMemberInterface[]>([]);
     const [ isSubmitting, setIsSubmitting ] = useState<boolean>(false);
     const [ existingGroupList, setExistingGroupList ] = useState([]);
 
@@ -136,7 +126,6 @@ export const UserGroupsList: FunctionComponent<UserGroupsPropsInterface> = (
             return;
         }
         mapUserGroups();
-        setAssignedGroups(user.groups);
     }, []);
 
     /**
@@ -176,7 +165,6 @@ export const UserGroupsList: FunctionComponent<UserGroupsPropsInterface> = (
             return;
         }
         mapUserGroups();
-        setAssignedGroups(user.groups);
     }, [ user ]);
 
     useEffect(() => {
@@ -542,174 +530,16 @@ export const UserGroupsList: FunctionComponent<UserGroupsPropsInterface> = (
         </Modal>
     );
 
-    const handleAssignedGroupListSearch = (e: ChangeEvent<HTMLInputElement>, { value }: { value: string }) => {
-        let isMatch: boolean = false;
-        const filteredGroupList: RolesMemberInterface[] = [];
-
-        if (!isEmpty(value)) {
-            const re: RegExp = new RegExp(escapeRegExp(value), "i");
-
-            assignedGroups && assignedGroups?.map((group: RolesMemberInterface) => {
-                const groupName: string[] = group?.display?.split("/");
-
-                if (groupName.length === 1) {
-                    isMatch = re.test(group.display);
-                    if (isMatch) {
-                        filteredGroupList.push(group);
-                        setAssignedGroups(filteredGroupList);
-                    }
-                }
-            });
-        } else {
-            setAssignedGroups(user.groups);
-        }
-    };
-
-    const resolveTableContent = (): ReactElement => {
-        return (
-            <Table.Body>
-                {
-                    assignedGroups?.map((group: RolesMemberInterface, index: number) => {
-                        const userGroup: string[] = group?.display?.split("/");
-
-                        if (userGroup[0] !== APPLICATION_DOMAIN &&
-                            userGroup[0] !== INTERNAL_DOMAIN) {
-                            return (
-                                <Table.Row key={ index }>
-                                    <Table.Cell>
-                                        {
-                                            userGroup?.length === 1
-                                                ? (<Label color="olive">
-                                                    {
-                                                        StringUtils.isEqualCaseInsensitive(
-                                                            primaryUserStoreDomainName, PRIMARY_USERSTORE)
-                                                            ? t("console:manage.features.users.userstores" +
-                                                                ".userstoreOptions.primary")
-                                                            : primaryUserStoreDomainName
-                                                    }
-                                                </Label>)
-                                                : (<Label color="olive">
-                                                    { userGroup[0] }
-                                                </Label>)
-                                        }
-                                    </Table.Cell>
-                                    <Table.Cell>
-                                        {
-                                            userGroup?.length === 1
-                                                ? group?.display
-                                                : userGroup[1]
-                                        }
-                                    </Table.Cell>
-                                </Table.Row>
-                            );
-                        }
-                    })
-                }
-            </Table.Body>
-        );
-    };
-
     return (
-        <EmphasizedSegment padded="very">
-            <Heading as="h4">
-                { t("user:updateUser.groups.editGroups.heading") }
-            </Heading>
-            <Heading subHeading ellipsis as="h6">
-                { t("user:updateUser.groups.editGroups.subHeading") }
-            </Heading>
-            <Divider hidden/>
-            <Grid>
-                <Grid.Row>
-                    <Grid.Column computer={ 10 } tablet={ 16 } mobile={ 16 }>
-                        {
-                            primaryGroupsList?.size > 0 ? (
-                                <EmphasizedSegment
-                                    data-testid="user-mgt-groups-list"
-                                    className="user-role-edit-header-segment"
-                                >
-                                    <Grid.Row>
-                                        <Grid.Column>
-                                            <Input
-                                                data-testid="user-mgt-groups-list-search-input"
-                                                icon={ <Icon name="search"/> }
-                                                onChange={ handleAssignedGroupListSearch }
-                                                placeholder={ t("user:updateUser.groups." +
-                                                    "editGroups.searchPlaceholder") }
-                                                floated="left"
-                                                size="small"
-                                            />
-                                            {
-                                                !isReadOnly && (
-                                                    <Button
-                                                        data-testid="user-mgt-groups-list-update-button"
-                                                        size="medium"
-                                                        icon="pencil"
-                                                        floated="right"
-                                                        onClick={ handleOpenAddNewGroupModal }
-                                                    />
-                                                )
-                                            }
-                                        </Grid.Column>
-                                    </Grid.Row>
-                                    <Grid.Row>
-                                        <Table singleLine compact>
-                                            <Table.Header>
-                                                <Table.Row>
-                                                    <Table.HeaderCell>
-                                                        <strong>
-                                                            { t("user:updateUser.groups." +
-                                                                "editGroups.groupList.headers.0") }
-                                                        </strong>
-                                                    </Table.HeaderCell>
-                                                    <Table.HeaderCell>
-                                                        <strong>
-                                                            { t("user:updateUser.groups." +
-                                                                "editGroups.groupList.headers.1") }
-                                                        </strong>
-                                                    </Table.HeaderCell>
-                                                </Table.Row>
-                                            </Table.Header>
-                                            { resolveTableContent() }
-                                        </Table>
-                                    </Grid.Row>
-                                </EmphasizedSegment>
-                            ) : (
-                                <EmphasizedSegment>
-                                    <EmptyPlaceholder
-                                        data-testid="user-mgt-empty-groups-list"
-                                        title={ t("user:updateUser.groups.editGroups." +
-                                            "groupList.emptyListPlaceholder.title") }
-                                        subtitle={ [
-                                            t("user:updateUser.groups.editGroups." +
-                                                    "groupList.emptyListPlaceholder.subTitle.0"),
-                                            t("user:updateUser.groups.editGroups." +
-                                                "groupList.emptyListPlaceholder.subTitle.1"),
-                                            t("user:updateUser.groups.editGroups." +
-                                                "groupList.emptyListPlaceholder.subTitle.2")
-                                        ] }
-                                        action={
-                                            !isReadOnly && (
-                                                <PrimaryButton
-                                                    data-testid="user-mgt-empty-groups-list-assign-group-button"
-                                                    onClick={ handleOpenAddNewGroupModal }
-                                                    loading={ isLoading }
-                                                    disabled={ isLoading }
-                                                >
-                                                    <Icon name="plus"/>
-                                                    Assign Group
-                                                </PrimaryButton>
-                                            )
-                                        }
-                                        image={ getEmptyPlaceholderIllustrations().emptyList }
-                                        imageSize="tiny"
-                                    />
-                                </EmphasizedSegment>
-                            )
-                        }
-                    </Grid.Column>
-                </Grid.Row>
-            </Grid>
+        <>
+            <UserGroupsListTable
+                handleOpenAddNewGroupModal={ handleOpenAddNewGroupModal }
+                handleUserUpdate={ handleUserUpdate }
+                isLoading={ isLoading }
+                isReadOnly={ isReadOnly }
+                user={ user }
+            />
             { addNewGroupModal() }
-        </EmphasizedSegment>
+        </>
     );
 };
diff --git a/features/admin.users.v1/components/user-groups-list.tsx b/features/admin.users.v1/components/user-groups-list.tsx
new file mode 100644
index 00000000000..0728a188665
--- /dev/null
+++ b/features/admin.users.v1/components/user-groups-list.tsx
@@ -0,0 +1,497 @@
+/**
+ * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import Box from "@oxygen-ui/react/Box";
+import { AdvancedSearchWithBasicFilters } from "@wso2is/admin.core.v1/components/advanced-search-with-basic-filters";
+import { getEmptyPlaceholderIllustrations } from "@wso2is/admin.core.v1/configs/ui";
+import { UIConstants } from "@wso2is/admin.core.v1/constants/ui-constants";
+import { userstoresConfig } from "@wso2is/admin.extensions.v1";
+import { updateGroupDetails } from "@wso2is/admin.groups.v1/api/groups";
+import { GroupsMemberInterface, PatchGroupDataInterface } from "@wso2is/admin.groups.v1/models/groups";
+import {
+    AlertLevels,
+    IdentifiableComponentInterface,
+    ProfileInfoInterface
+} from "@wso2is/core/models";
+import { addAlert } from "@wso2is/core/store";
+import {
+    ConfirmationModal,
+    DataTable,
+    EmphasizedSegment,
+    EmptyPlaceholder,
+    Heading,
+    LinkButton,
+    ListLayout,
+    PrimaryButton,
+    TableActionsInterface,
+    TableColumnInterface,
+    UserAvatar
+} from "@wso2is/react-components";
+import isEmpty from "lodash-es/isEmpty";
+import React, {
+    FunctionComponent,
+    ReactElement,
+    ReactNode,
+    SyntheticEvent,
+    useEffect,
+    useState
+} from "react";
+import { useTranslation } from "react-i18next";
+import { useDispatch } from "react-redux";
+import { Dispatch } from "redux";
+import { Divider, DropdownProps, Header, Icon, Label, PaginationProps, SemanticICONS } from "semantic-ui-react";
+import "./user-roles-list.scss";
+
+interface UserGroupsEditPropsInterface extends IdentifiableComponentInterface {
+    /**
+     * User profile
+     */
+    user: ProfileInfoInterface;
+    /**
+     * Is the component loading
+     */
+    isLoading?: boolean;
+    /**
+     * Is the component in read only mode
+     */
+    isReadOnly?: boolean;
+    /**
+     * Callback to open the add new group modal
+     */
+    handleOpenAddNewGroupModal: () => void;
+    /**
+     * Handle user update callback.
+     */
+    handleUserUpdate: (userId: string) => void;
+}
+
+/**
+ * User groups list component.
+ *
+ * @param props - Props injected to the component.
+ *
+ * @returns User groups list component.
+ */
+export const UserGroupsListTable: FunctionComponent<UserGroupsEditPropsInterface> = (
+    props: UserGroupsEditPropsInterface
+): ReactElement => {
+
+    const {
+        user,
+        isLoading,
+        isReadOnly,
+        handleOpenAddNewGroupModal,
+        handleUserUpdate,
+        "data-componentid": componentId = "edit-user-groups"
+    } = props;
+
+    const { t } = useTranslation();
+
+    const dispatch: Dispatch = useDispatch();
+
+    const [ searchQuery, setSearchQuery ] = useState<string>("");
+    const [ listItemLimit, setListItemLimit ] = useState<number>(UIConstants.DEFAULT_RESOURCE_LIST_ITEM_LIMIT);
+    const [ listOffset, setListOffset ] = useState<number>(0);
+    const [ paginatedGroups, setPaginatedGroups ] = useState<GroupsMemberInterface[]>(undefined);
+    const [ triggerClearQuery, setTriggerClearQuery ] = useState<boolean>(false);
+    const [ showDeleteConfirmationModal, setShowDeleteConfirmationModal ] = useState<boolean>(false);
+    const [ deletingGroup, setDeletingGroup ] = useState<GroupsMemberInterface>(undefined);
+    const [ isDeleting, setDeleting ] = useState<boolean>(false);
+
+    const userGroupsList: GroupsMemberInterface[] = user?.groups;
+
+    /**
+     * Set initial selected roles options
+     */
+    useEffect(() => {
+        resolvePaginatedGroupsList(0, listItemLimit, userGroupsList, searchQuery);
+    }, [ user, searchQuery ]);
+
+    /**
+     * Util method to paginate retrieved groups list.
+     *
+     * @param offsetValue - pagination offset value.
+     * @param itemLimit - pagination item limit.
+     * @param list - Role list.
+     * @param searchQuery - Search query.
+     */
+    const resolvePaginatedGroupsList = (
+        offsetValue: number,
+        itemLimit: number,
+        list: GroupsMemberInterface[],
+        searchQuery?: string
+    ): void => {
+        if (!list) {
+            setPaginatedGroups([]);
+
+            return;
+        }
+
+        if (!isEmpty(searchQuery)) {
+            const filteredList: GroupsMemberInterface[] = list.filter((group: GroupsMemberInterface) => {
+                return group.display.toLowerCase().includes(searchQuery.toLowerCase());
+            });
+
+            setPaginatedGroups(filteredList?.slice(offsetValue, itemLimit + offsetValue));
+
+            return;
+        }
+
+        setPaginatedGroups(list?.slice(offsetValue, itemLimit + offsetValue));
+    };
+
+    const handlePaginationChange = (event: React.MouseEvent<HTMLAnchorElement>, data: PaginationProps): void => {
+        const offsetValue: number = (data.activePage as number - 1) * listItemLimit;
+
+        setListOffset(offsetValue);
+        resolvePaginatedGroupsList(offsetValue, listItemLimit, userGroupsList);
+    };
+
+    const handleItemsPerPageDropdownChange = (
+        event: React.MouseEvent<HTMLAnchorElement>,
+        data: DropdownProps
+    ): void => {
+        setListItemLimit(data.value as number);
+        resolvePaginatedGroupsList(listOffset, data.value as number, userGroupsList);
+    };
+
+    const handleSearchQueryClear = (): void => {
+        setTriggerClearQuery(!triggerClearQuery);
+        setSearchQuery("");
+    };
+
+    const resolveTotalPages = (): number => {
+        return Math.ceil(userGroupsList?.length / listItemLimit);
+    };
+
+    /**
+     * Unassign a user from a group.
+     *
+     * @param group - Group to be unassigned.
+     */
+    const unassignUserFromGroup = (group: GroupsMemberInterface): void => {
+        const operationData: PatchGroupDataInterface = {
+            Operations: [ {
+                "op": "remove",
+                "path": `members[value eq ${user.id}]`
+            } ],
+            schemas: [ "urn:ietf:params:scim:api:messages:2.0:PatchOp" ]
+        };
+
+        updateGroupDetails(group.value, operationData)
+            .then(() => {
+                dispatch(addAlert({
+                    description: t("console:manage.features.groups.notifications.updateGroup.success.description"),
+                    level: AlertLevels.SUCCESS,
+                    message: t("console:manage.features.groups.notifications.updateGroup.success.message")
+                }));
+                handleUserUpdate(user.id);
+            }).catch(() => {
+                dispatch(addAlert({
+                    description: t("console:manage.features.groups.notifications.updateGroup.error.description"),
+                    level: AlertLevels.ERROR,
+                    message: t("console:manage.features.groups.notifications.updateGroup.error.message")
+                }));
+            }).finally(() => {
+                setDeleting(false);
+                setDeletingGroup(undefined);
+                setShowDeleteConfirmationModal(false);
+            });
+    };
+
+    /**
+     * Resolves data table columns.
+     *
+     * @returns the data table columns.
+     */
+    const resolveTableColumns = (): TableColumnInterface[] => {
+        const defaultColumns: TableColumnInterface[] = [
+            {
+                allowToggleVisibility: false,
+                dataIndex: "groupName",
+                id: "groupName",
+                key: "groupName",
+                render: (group: GroupsMemberInterface): ReactNode => {
+                    const groupNameSegments: string[] = group?.display?.split("/");
+                    const userGroupName: string = groupNameSegments.length === 1
+                        ? groupNameSegments[0]
+                        : groupNameSegments[1];
+
+                    return (
+                        <Header
+                            image
+                            as="h6"
+                            className="header-with-icon"
+                            data-componentid={ `${ componentId }-item-heading` }
+                        >
+                            <UserAvatar
+                                data-componentid="users-list-item-image"
+                                name={ group.display }
+                                size="mini"
+                                image={ user.profileUrl }
+                                spaced="right"
+                                data-suppress=""
+                            />
+                            <div>
+                                { userGroupName as ReactNode }
+                            </div>
+                        </Header>
+                    );
+                },
+                title: (
+                    <div className="pl-3">
+                        { t("user:updateUser.groups.editGroups.groupList.headers.1") }
+                    </div>
+                )
+            },
+            {
+                allowToggleVisibility: false,
+                dataIndex: "domain",
+                id: "domain",
+                key: "domain",
+                render: (group: GroupsMemberInterface): ReactNode => {
+                    const groupNameSegments: string[] = group?.display?.split("/");
+                    const domain: string = groupNameSegments.length === 1
+                        ? userstoresConfig.primaryUserstoreName
+                        : groupNameSegments[0];
+
+                    return (
+                        <Header
+                            image
+                            as="h6"
+                            className="header-with-icon"
+                            data-componentid={ `${ componentId }-item-heading` }
+                        >
+                            <Label size="mini">
+                                { domain }
+                            </Label>
+                        </Header>
+                    );
+                },
+                title: (
+                    <div className="pl-3">
+                        { t("user:updateUser.groups.editGroups.groupList.headers.0") }
+                    </div>
+                )
+            }
+        ];
+
+        defaultColumns.push(
+            {
+                allowToggleVisibility: false,
+                dataIndex: "action",
+                id: "actions",
+                key: "actions",
+                textAlign: "right",
+                title: ""
+            }
+        );
+
+        return defaultColumns;
+    };
+
+    /**
+     * Resolves data table actions.
+     *
+     * @returns Table actions.
+     */
+    const resolveTableActions = (): TableActionsInterface[] => {
+        const actions: TableActionsInterface[] = [
+            {
+                "data-componentid": `${ componentId }-user-list-item-delete-button`,
+                "data-testid": `${ componentId }-user-list-item-delete-button`,
+                hidden: (): boolean => isReadOnly,
+                icon: (): SemanticICONS =>  "trash alternate",
+                onClick: (e: SyntheticEvent, group: GroupsMemberInterface): void => {
+                    setDeletingGroup(group);
+                    setShowDeleteConfirmationModal(true);
+                },
+                popupText: (): string => t("common:delete"),
+                renderer: "semantic-icon"
+            }
+        ];
+
+        return actions;
+    };
+
+    /**
+     * Shows list placeholders.
+     *
+     * @returns Placeholders.
+     */
+    const showPlaceholders = (): ReactElement => {
+        if (searchQuery) {
+            return (
+                <EmptyPlaceholder
+                    action={ (
+                        <LinkButton onClick={ handleSearchQueryClear }>
+                            { t("users:usersList.search.emptyResultPlaceholder.clearButton") }
+                        </LinkButton>
+                    ) }
+                    image={ getEmptyPlaceholderIllustrations().emptySearch }
+                    imageSize="tiny"
+                    data-testid="user-mgt-empty-groups-list"
+                    title={ t("user:updateUser.groups.editGroups." +
+                        "groupList.emptyListPlaceholder.title") }
+                    subtitle={ [
+                        t("roles:list.emptyPlaceholders.search.subtitles.0",
+                            { searchQuery: searchQuery }),
+                        t("roles:list.emptyPlaceholders.search.subtitles.1")
+                    ] }
+                />
+            );
+        }
+
+        if (paginatedGroups?.length === 0) {
+            return (
+                <EmptyPlaceholder
+                    data-testid="user-mgt-empty-groups-list"
+                    title={ t("user:updateUser.groups.editGroups." +
+                        "groupList.emptyListPlaceholder.title") }
+                    subtitle={ [
+                        t("user:updateUser.groups.editGroups." +
+                                "groupList.emptyListPlaceholder.subTitle.0"),
+                        t("user:updateUser.groups.editGroups." +
+                            "groupList.emptyListPlaceholder.subTitle.1"),
+                        t("user:updateUser.groups.editGroups." +
+                            "groupList.emptyListPlaceholder.subTitle.2")
+                    ] }
+                    action={
+                        !isReadOnly && (
+                            <PrimaryButton
+                                data-testid="user-mgt-empty-groups-list-assign-group-button"
+                                onClick={ handleOpenAddNewGroupModal }
+                                loading={ isLoading }
+                                disabled={ isLoading }
+                            >
+                                <Icon name="plus"/>
+                                { t("applicationRoles:roleGroups.assignGroup") }
+                            </PrimaryButton>
+                        )
+                    }
+                    image={ getEmptyPlaceholderIllustrations().emptyList }
+                    imageSize="tiny"
+                />
+            );
+        }
+
+        return null;
+    };
+
+    return (
+        <EmphasizedSegment
+            className="list-user-roles-section"
+            data-testid="user-mgt-groups-list"
+            padded="very"
+        >
+            <Box display="flex" justifyContent="space-between" alignItems="center">
+                {
+                    (!!searchQuery || paginatedGroups?.length > 0) &&  (
+                        <div>
+                            <Heading as="h4">
+                                { t("user:updateUser.groups.editGroups.heading") }
+                            </Heading>
+                            <Heading subHeading ellipsis as="h6">
+                                { t("user:updateUser.groups.editGroups.subHeading") }
+                            </Heading>
+                        </div>
+                    )
+                }
+                { !isReadOnly && (!!searchQuery || paginatedGroups?.length > 0) && (
+                    <PrimaryButton
+                        data-testid="user-mgt-groups-list-update-button"
+                        onClick={ handleOpenAddNewGroupModal }
+                    >
+                        <Icon name="plus"/>
+                        { t("applicationRoles:roleGroups.assignGroup") }
+                    </PrimaryButton>
+                ) }
+            </Box>
+            <Divider hidden/>
+            <ListLayout
+                advancedSearch={ (
+                    <AdvancedSearchWithBasicFilters
+                        data-testid="group-mgt-groups-list-advanced-search"
+                        onFilter={ (query: string) => setSearchQuery(query?.trim()) }
+                        disableSearchFilterDropdown
+                        filterAttributeOptions={ [] }
+                        placeholder={ t("console:manage.features.groups.advancedSearch.placeholder") }
+                        defaultSearchAttribute=""
+                        defaultSearchOperator=""
+                        triggerClearQuery={ triggerClearQuery }
+                    />
+                ) }
+                currentListSize={ paginatedGroups?.length }
+                listItemLimit={ listItemLimit }
+                onItemsPerPageDropdownChange={ handleItemsPerPageDropdownChange }
+                data-componentid={ `${ componentId }-user-groups-list-layout` }
+                data-testid={ `${ componentId }-user-groups-list-layout` }
+                onPageChange={ handlePaginationChange }
+                showPagination={ true }
+                totalPages={ resolveTotalPages() }
+                totalListSize={ userGroupsList?.length }
+                showPaginationPageLimit={ !isReadOnly }
+                showTopActionPanel={ (!!searchQuery || userGroupsList?.length > 0) }
+            >
+                <DataTable<GroupsMemberInterface>
+                    isLoading={ isLoading }
+                    loadingStateOptions={ {
+                        count: UIConstants.DEFAULT_RESOURCE_LIST_ITEM_LIMIT,
+                        imageType: "circular"
+                    } }
+                    actions={ resolveTableActions() }
+                    columns={ resolveTableColumns() }
+                    data={ paginatedGroups }
+                    onRowClick={ () =>  null }
+                    placeholders={ showPlaceholders() }
+                    selectable={ false }
+                    showHeader={ true }
+                    data-testid={ componentId }
+                />
+            </ListLayout>
+            <ConfirmationModal
+                primaryActionLoading={ isDeleting }
+                data-componentid={ `${ componentId }-confirmation-modal` }
+                onClose={ (): void => setShowDeleteConfirmationModal(false) }
+                type="negative"
+                open={ showDeleteConfirmationModal }
+                primaryAction={ t("common:confirm") }
+                secondaryAction={ t("common:cancel") }
+                onSecondaryActionClick={ (): void => {
+                    setShowDeleteConfirmationModal(false);
+                } }
+                onPrimaryActionClick={ (): void => {
+                    setDeleting(true);
+                    unassignUserFromGroup(deletingGroup);
+                } }
+                closeOnDimmerClick={ false }
+            >
+                <ConfirmationModal.Header
+                    data-componentid={ `${ componentId }-confirmation-modal-header` }
+                >
+                    { t("users:confirmations.unassignGroup.header") }
+                </ConfirmationModal.Header>
+                <ConfirmationModal.Content
+                    data-componentid={ `${ componentId }-confirmation-modal-content` }
+                >
+                    { t("users:confirmations.unassignGroup.content") }
+                </ConfirmationModal.Content>
+            </ConfirmationModal>
+        </EmphasizedSegment>
+    );
+};
diff --git a/modules/i18n/src/models/namespaces/users-ns.ts b/modules/i18n/src/models/namespaces/users-ns.ts
index f73357c54de..f10bf85e9fd 100644
--- a/modules/i18n/src/models/namespaces/users-ns.ts
+++ b/modules/i18n/src/models/namespaces/users-ns.ts
@@ -74,6 +74,11 @@ export interface usersNS {
             message: string;
             content: string;
         };
+        unassignGroup: {
+            assertionHint: string;
+            header: string;
+            content: string;
+        };
     };
     editUser: {
         tab: {
diff --git a/modules/i18n/src/translations/en-US/portals/users.ts b/modules/i18n/src/translations/en-US/portals/users.ts
index 0f40e79d052..41ca5f0824a 100644
--- a/modules/i18n/src/translations/en-US/portals/users.ts
+++ b/modules/i18n/src/translations/en-US/portals/users.ts
@@ -84,6 +84,12 @@ export const users: usersNS = {
                 "session. They will loose the progress of any ongoing tasks. Please proceed with caution.",
             header: "Are you sure?",
             message: "This action is irreversible and will permanently terminate the session."
+        },
+        unassignGroup: {
+            assertionHint: "Please confirm your action.",
+            content: "If you proceed with this action, the user will be unassigned from the selected group. " +
+                "Note that this may affect the user when performing certain tasks.",
+            header: "Are you sure?"
         }
     },
     consumerUsers: {


Reviews:
user: login: pavinduLakshan
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-20T15:26:55Z
user: login: pavinduLakshan
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-20T15:28:21Z
user: login: pavinduLakshan
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-20T15:29:17Z
user: login: pavinduLakshan
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-20T15:32:17Z
user: login: pavinduLakshan
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-20T15:33:16Z
user: login: pavinduLakshan
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-20T15:36:09Z
user: login: pavinduLakshan
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-20T15:38:47Z
user: login: pavinduLakshan
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-20T15:40:17Z
user: login: pavinduLakshan
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-20T15:41:14Z
user: login: pavinduLakshan
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-20T15:42:42Z
user: login: pavinduLakshan
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-20T15:44:04Z
user: login: pavinduLakshan
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-20T15:44:50Z
user: login: DonOmalVindula
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T11:17:09Z
user: login: DonOmalVindula
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T11:17:16Z
user: login: DonOmalVindula
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T11:17:24Z
user: login: DonOmalVindula
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T11:17:38Z
user: login: DonOmalVindula
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T11:17:43Z
user: login: DonOmalVindula
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T11:17:48Z
user: login: DonOmalVindula
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T11:17:53Z
user: login: DonOmalVindula
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T11:18:00Z
user: login: DonOmalVindula
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T11:18:06Z
user: login: DonOmalVindula
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T11:18:13Z
user: login: DonOmalVindula
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T11:18:18Z
user: login: pavinduLakshan
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-22T02:28:22Z

Review comments:
diff_hunk: @@ -0,0 +1,6 @@
+---
+"@wso2is/admin.users.v1": patch
+"@wso2is/i18n": patch
+---
path: .changeset/curvy-insects-design.md
user: login: pavinduLakshan
body: Let's bump console too, otherwise users.v1 dependency in console will not be updated
created_at: 2025-03-20T15:26:55Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,493 @@
+/**
+ * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import Box from "@oxygen-ui/react/Box/Box";
path: features/admin.users.v1/components/user-groups-list.tsx
user: login: pavinduLakshan
body: Hope you meant this?

```suggestion
import Box from "@oxygen-ui/react/Box";
```
created_at: 2025-03-20T15:28:21Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,493 @@
+/**
+ * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import Box from "@oxygen-ui/react/Box/Box";
+import { AdvancedSearchWithBasicFilters } from "@wso2is/admin.core.v1/components/advanced-search-with-basic-filters";
+import { getEmptyPlaceholderIllustrations } from "@wso2is/admin.core.v1/configs/ui";
+import { UIConstants } from "@wso2is/admin.core.v1/constants/ui-constants";
+import { userstoresConfig } from "@wso2is/admin.extensions.v1";
+import { updateGroupDetails } from "@wso2is/admin.groups.v1/api/groups";
+import { GroupsMemberInterface, PatchGroupDataInterface } from "@wso2is/admin.groups.v1/models/groups";
+import {
+    AlertLevels,
+    IdentifiableComponentInterface,
+    ProfileInfoInterface
+} from "@wso2is/core/models";
+import { addAlert } from "@wso2is/core/store";
+import {
+    ConfirmationModal,
+    DataTable,
+    EmphasizedSegment,
+    EmptyPlaceholder,
+    Heading,
+    LinkButton,
+    ListLayout,
+    PrimaryButton,
+    TableActionsInterface,
+    TableColumnInterface,
+    UserAvatar
+} from "@wso2is/react-components";
+import isEmpty from "lodash-es/isEmpty";
+import React, {
+    FunctionComponent,
+    ReactElement,
+    ReactNode,
+    SyntheticEvent,
+    useEffect,
+    useState
+} from "react";
+import { useTranslation } from "react-i18next";
+import { useDispatch } from "react-redux";
+import { Dispatch } from "redux";
+import { Divider, DropdownProps, Header, Icon, Label, PaginationProps, SemanticICONS } from "semantic-ui-react";
+import "./user-roles-list.scss";
+
+interface UserGroupsEditPropsInterface extends IdentifiableComponentInterface {
+    /**
+     * User profile
+     */
+    user: ProfileInfoInterface;
+    /**
+     * Is the component loading
+     */
+    isLoading?: boolean;
+    /**
+     * Is the component in read only mode
+     */
+    isReadOnly?: boolean;
+    /**
+     * Callback to open the add new group modal
+     */
+    handleOpenAddNewGroupModal: () => void;
+    /**
+     * Handle user update callback.
+     */
+    handleUserUpdate: (userId: string) => void;
+}
+
+export const UserGroupsListTable: FunctionComponent<UserGroupsEditPropsInterface> = (
path: features/admin.users.v1/components/user-groups-list.tsx
user: login: pavinduLakshan
body: Let's add a doc comment
created_at: 2025-03-20T15:29:17Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,493 @@
+/**
+ * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import Box from "@oxygen-ui/react/Box/Box";
+import { AdvancedSearchWithBasicFilters } from "@wso2is/admin.core.v1/components/advanced-search-with-basic-filters";
+import { getEmptyPlaceholderIllustrations } from "@wso2is/admin.core.v1/configs/ui";
+import { UIConstants } from "@wso2is/admin.core.v1/constants/ui-constants";
+import { userstoresConfig } from "@wso2is/admin.extensions.v1";
+import { updateGroupDetails } from "@wso2is/admin.groups.v1/api/groups";
+import { GroupsMemberInterface, PatchGroupDataInterface } from "@wso2is/admin.groups.v1/models/groups";
+import {
+    AlertLevels,
+    IdentifiableComponentInterface,
+    ProfileInfoInterface
+} from "@wso2is/core/models";
+import { addAlert } from "@wso2is/core/store";
+import {
+    ConfirmationModal,
+    DataTable,
+    EmphasizedSegment,
+    EmptyPlaceholder,
+    Heading,
+    LinkButton,
+    ListLayout,
+    PrimaryButton,
+    TableActionsInterface,
+    TableColumnInterface,
+    UserAvatar
+} from "@wso2is/react-components";
+import isEmpty from "lodash-es/isEmpty";
+import React, {
+    FunctionComponent,
+    ReactElement,
+    ReactNode,
+    SyntheticEvent,
+    useEffect,
+    useState
+} from "react";
+import { useTranslation } from "react-i18next";
+import { useDispatch } from "react-redux";
+import { Dispatch } from "redux";
+import { Divider, DropdownProps, Header, Icon, Label, PaginationProps, SemanticICONS } from "semantic-ui-react";
+import "./user-roles-list.scss";
+
+interface UserGroupsEditPropsInterface extends IdentifiableComponentInterface {
+    /**
+     * User profile
+     */
+    user: ProfileInfoInterface;
+    /**
+     * Is the component loading
+     */
+    isLoading?: boolean;
+    /**
+     * Is the component in read only mode
+     */
+    isReadOnly?: boolean;
+    /**
+     * Callback to open the add new group modal
+     */
+    handleOpenAddNewGroupModal: () => void;
+    /**
+     * Handle user update callback.
+     */
+    handleUserUpdate: (userId: string) => void;
+}
+
+export const UserGroupsListTable: FunctionComponent<UserGroupsEditPropsInterface> = (
+    props: UserGroupsEditPropsInterface
+): ReactElement => {
+
+    const {
+        user,
+        isLoading,
+        isReadOnly,
+        handleOpenAddNewGroupModal,
+        handleUserUpdate,
+        "data-componentid": componentId
+    } = props;
+
+    const { t } = useTranslation();
+
+    const dispatch: Dispatch = useDispatch();
+
+    const [ searchQuery, setSearchQuery ] = useState<string>("");
+    const [ listItemLimit, setListItemLimit ] = useState<number>(UIConstants.DEFAULT_RESOURCE_LIST_ITEM_LIMIT);
+    const [ listOffset, setListOffset ] = useState<number>(0);
+    const [ paginatedGroups, setPaginatedGroups ] = useState<GroupsMemberInterface[]>(undefined);
+    const [ triggerClearQuery, setTriggerClearQuery ] = useState<boolean>(false);
+    const [ showDeleteConfirmationModal, setShowDeleteConfirmationModal ] = useState<boolean>(false);
+    const [ deletingGroup, setDeletingGroup ] = useState<GroupsMemberInterface>(undefined);
+    const [ isDeleting, setDeleting ] = useState<boolean>(false);
+
+    const userGroupsList: GroupsMemberInterface[] = user?.groups;
+
+    /**
+     * Set initial selected roles options
+     */
+    useEffect(() => {
+        setGroupsPage(0, listItemLimit, userGroupsList, searchQuery);
path: features/admin.users.v1/components/user-groups-list.tsx
user: login: pavinduLakshan
body: the function name looks like a setter of a react state variable. shall we update the function name?
created_at: 2025-03-20T15:32:17Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,493 @@
+/**
+ * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import Box from "@oxygen-ui/react/Box/Box";
+import { AdvancedSearchWithBasicFilters } from "@wso2is/admin.core.v1/components/advanced-search-with-basic-filters";
+import { getEmptyPlaceholderIllustrations } from "@wso2is/admin.core.v1/configs/ui";
+import { UIConstants } from "@wso2is/admin.core.v1/constants/ui-constants";
+import { userstoresConfig } from "@wso2is/admin.extensions.v1";
+import { updateGroupDetails } from "@wso2is/admin.groups.v1/api/groups";
+import { GroupsMemberInterface, PatchGroupDataInterface } from "@wso2is/admin.groups.v1/models/groups";
+import {
+    AlertLevels,
+    IdentifiableComponentInterface,
+    ProfileInfoInterface
+} from "@wso2is/core/models";
+import { addAlert } from "@wso2is/core/store";
+import {
+    ConfirmationModal,
+    DataTable,
+    EmphasizedSegment,
+    EmptyPlaceholder,
+    Heading,
+    LinkButton,
+    ListLayout,
+    PrimaryButton,
+    TableActionsInterface,
+    TableColumnInterface,
+    UserAvatar
+} from "@wso2is/react-components";
+import isEmpty from "lodash-es/isEmpty";
+import React, {
+    FunctionComponent,
+    ReactElement,
+    ReactNode,
+    SyntheticEvent,
+    useEffect,
+    useState
+} from "react";
+import { useTranslation } from "react-i18next";
+import { useDispatch } from "react-redux";
+import { Dispatch } from "redux";
+import { Divider, DropdownProps, Header, Icon, Label, PaginationProps, SemanticICONS } from "semantic-ui-react";
+import "./user-roles-list.scss";
+
+interface UserGroupsEditPropsInterface extends IdentifiableComponentInterface {
+    /**
+     * User profile
+     */
+    user: ProfileInfoInterface;
+    /**
+     * Is the component loading
+     */
+    isLoading?: boolean;
+    /**
+     * Is the component in read only mode
+     */
+    isReadOnly?: boolean;
+    /**
+     * Callback to open the add new group modal
+     */
+    handleOpenAddNewGroupModal: () => void;
+    /**
+     * Handle user update callback.
+     */
+    handleUserUpdate: (userId: string) => void;
+}
+
+export const UserGroupsListTable: FunctionComponent<UserGroupsEditPropsInterface> = (
+    props: UserGroupsEditPropsInterface
+): ReactElement => {
+
+    const {
+        user,
+        isLoading,
+        isReadOnly,
+        handleOpenAddNewGroupModal,
+        handleUserUpdate,
+        "data-componentid": componentId
+    } = props;
+
+    const { t } = useTranslation();
+
+    const dispatch: Dispatch = useDispatch();
+
+    const [ searchQuery, setSearchQuery ] = useState<string>("");
+    const [ listItemLimit, setListItemLimit ] = useState<number>(UIConstants.DEFAULT_RESOURCE_LIST_ITEM_LIMIT);
+    const [ listOffset, setListOffset ] = useState<number>(0);
+    const [ paginatedGroups, setPaginatedGroups ] = useState<GroupsMemberInterface[]>(undefined);
+    const [ triggerClearQuery, setTriggerClearQuery ] = useState<boolean>(false);
+    const [ showDeleteConfirmationModal, setShowDeleteConfirmationModal ] = useState<boolean>(false);
+    const [ deletingGroup, setDeletingGroup ] = useState<GroupsMemberInterface>(undefined);
+    const [ isDeleting, setDeleting ] = useState<boolean>(false);
+
+    const userGroupsList: GroupsMemberInterface[] = user?.groups;
+
+    /**
+     * Set initial selected roles options
+     */
+    useEffect(() => {
+        setGroupsPage(0, listItemLimit, userGroupsList, searchQuery);
+    }, [ user, searchQuery ]);
+
+    /**
+     * Util method to paginate retrieved groups  list.
+     *
+     * @param offsetValue - pagination offset value.
+     * @param itemLimit - pagination item limit.
+     * @param list - Role list.
+     */
+    const setGroupsPage = (
+        offsetValue: number,
+        itemLimit: number,
+        list: GroupsMemberInterface[],
+        searchQuery?: string
+    ) => {
+        if (!list) {
+            setPaginatedGroups([]);
+
+            return;
+        }
+
+        if (!isEmpty(searchQuery)) {
+            const filteredList: GroupsMemberInterface[] = list.filter((group: GroupsMemberInterface) => {
+                return group.display.toLowerCase().includes(searchQuery.toLowerCase());
+            });
+
+            setPaginatedGroups(filteredList?.slice(offsetValue, itemLimit + offsetValue));
+
+            return;
+        }
+
+        setPaginatedGroups(list?.slice(offsetValue, itemLimit + offsetValue));
+    };
+
+
+    const handlePaginationChange = (event: React.MouseEvent<HTMLAnchorElement>, data: PaginationProps) => {
+        const offsetValue: number = (data.activePage as number - 1) * listItemLimit;
+
+        setListOffset(offsetValue);
+        setGroupsPage(offsetValue, listItemLimit, userGroupsList);
+    };
+
+    const handleItemsPerPageDropdownChange = (event: React.MouseEvent<HTMLAnchorElement>, data: DropdownProps) => {
+        setListItemLimit(data.value as number);
+        setGroupsPage(listOffset, data.value as number, userGroupsList);
+    };
+
+    const handleSearchQueryClear = (): void => {
+        setTriggerClearQuery(!triggerClearQuery);
+        setSearchQuery("");
+    };
+
+    const resolveTotalPages = (): number => {
+        return Math.ceil(userGroupsList?.length / listItemLimit);
+    };
+
+    const unassignUserFromGroup = (group: GroupsMemberInterface) => {
path: features/admin.users.v1/components/user-groups-list.tsx
user: login: pavinduLakshan
body: Let's add doc comments for each function
created_at: 2025-03-20T15:33:15Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,493 @@
+/**
+ * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import Box from "@oxygen-ui/react/Box/Box";
+import { AdvancedSearchWithBasicFilters } from "@wso2is/admin.core.v1/components/advanced-search-with-basic-filters";
+import { getEmptyPlaceholderIllustrations } from "@wso2is/admin.core.v1/configs/ui";
+import { UIConstants } from "@wso2is/admin.core.v1/constants/ui-constants";
+import { userstoresConfig } from "@wso2is/admin.extensions.v1";
+import { updateGroupDetails } from "@wso2is/admin.groups.v1/api/groups";
+import { GroupsMemberInterface, PatchGroupDataInterface } from "@wso2is/admin.groups.v1/models/groups";
+import {
+    AlertLevels,
+    IdentifiableComponentInterface,
+    ProfileInfoInterface
+} from "@wso2is/core/models";
+import { addAlert } from "@wso2is/core/store";
+import {
+    ConfirmationModal,
+    DataTable,
+    EmphasizedSegment,
+    EmptyPlaceholder,
+    Heading,
+    LinkButton,
+    ListLayout,
+    PrimaryButton,
+    TableActionsInterface,
+    TableColumnInterface,
+    UserAvatar
+} from "@wso2is/react-components";
+import isEmpty from "lodash-es/isEmpty";
+import React, {
+    FunctionComponent,
+    ReactElement,
+    ReactNode,
+    SyntheticEvent,
+    useEffect,
+    useState
+} from "react";
+import { useTranslation } from "react-i18next";
+import { useDispatch } from "react-redux";
+import { Dispatch } from "redux";
+import { Divider, DropdownProps, Header, Icon, Label, PaginationProps, SemanticICONS } from "semantic-ui-react";
+import "./user-roles-list.scss";
+
+interface UserGroupsEditPropsInterface extends IdentifiableComponentInterface {
+    /**
+     * User profile
+     */
+    user: ProfileInfoInterface;
+    /**
+     * Is the component loading
+     */
+    isLoading?: boolean;
+    /**
+     * Is the component in read only mode
+     */
+    isReadOnly?: boolean;
+    /**
+     * Callback to open the add new group modal
+     */
+    handleOpenAddNewGroupModal: () => void;
+    /**
+     * Handle user update callback.
+     */
+    handleUserUpdate: (userId: string) => void;
+}
+
+export const UserGroupsListTable: FunctionComponent<UserGroupsEditPropsInterface> = (
+    props: UserGroupsEditPropsInterface
+): ReactElement => {
+
+    const {
+        user,
+        isLoading,
+        isReadOnly,
+        handleOpenAddNewGroupModal,
+        handleUserUpdate,
+        "data-componentid": componentId
+    } = props;
+
+    const { t } = useTranslation();
+
+    const dispatch: Dispatch = useDispatch();
+
+    const [ searchQuery, setSearchQuery ] = useState<string>("");
+    const [ listItemLimit, setListItemLimit ] = useState<number>(UIConstants.DEFAULT_RESOURCE_LIST_ITEM_LIMIT);
+    const [ listOffset, setListOffset ] = useState<number>(0);
+    const [ paginatedGroups, setPaginatedGroups ] = useState<GroupsMemberInterface[]>(undefined);
+    const [ triggerClearQuery, setTriggerClearQuery ] = useState<boolean>(false);
+    const [ showDeleteConfirmationModal, setShowDeleteConfirmationModal ] = useState<boolean>(false);
+    const [ deletingGroup, setDeletingGroup ] = useState<GroupsMemberInterface>(undefined);
+    const [ isDeleting, setDeleting ] = useState<boolean>(false);
+
+    const userGroupsList: GroupsMemberInterface[] = user?.groups;
+
+    /**
+     * Set initial selected roles options
+     */
+    useEffect(() => {
+        setGroupsPage(0, listItemLimit, userGroupsList, searchQuery);
+    }, [ user, searchQuery ]);
+
+    /**
+     * Util method to paginate retrieved groups  list.
+     *
+     * @param offsetValue - pagination offset value.
+     * @param itemLimit - pagination item limit.
+     * @param list - Role list.
+     */
+    const setGroupsPage = (
+        offsetValue: number,
+        itemLimit: number,
+        list: GroupsMemberInterface[],
+        searchQuery?: string
+    ) => {
+        if (!list) {
+            setPaginatedGroups([]);
+
+            return;
+        }
+
+        if (!isEmpty(searchQuery)) {
+            const filteredList: GroupsMemberInterface[] = list.filter((group: GroupsMemberInterface) => {
+                return group.display.toLowerCase().includes(searchQuery.toLowerCase());
+            });
+
+            setPaginatedGroups(filteredList?.slice(offsetValue, itemLimit + offsetValue));
+
+            return;
+        }
+
+        setPaginatedGroups(list?.slice(offsetValue, itemLimit + offsetValue));
+    };
+
+
+    const handlePaginationChange = (event: React.MouseEvent<HTMLAnchorElement>, data: PaginationProps) => {
+        const offsetValue: number = (data.activePage as number - 1) * listItemLimit;
+
+        setListOffset(offsetValue);
+        setGroupsPage(offsetValue, listItemLimit, userGroupsList);
+    };
+
+    const handleItemsPerPageDropdownChange = (event: React.MouseEvent<HTMLAnchorElement>, data: DropdownProps) => {
+        setListItemLimit(data.value as number);
+        setGroupsPage(listOffset, data.value as number, userGroupsList);
+    };
+
+    const handleSearchQueryClear = (): void => {
+        setTriggerClearQuery(!triggerClearQuery);
+        setSearchQuery("");
+    };
+
+    const resolveTotalPages = (): number => {
+        return Math.ceil(userGroupsList?.length / listItemLimit);
+    };
+
+    const unassignUserFromGroup = (group: GroupsMemberInterface) => {
+        const operationData: PatchGroupDataInterface = {
+            Operations: [ {
+                "op": "remove",
+                "path": `members[value eq ${user.id}]`
+            } ],
+            schemas: [ "urn:ietf:params:scim:api:messages:2.0:PatchOp" ]
+        };
+
+        updateGroupDetails(group.value, operationData)
+            .then(() => {
+                dispatch(addAlert({
+                    description: t("console:manage.features.groups.notifications.updateGroup.success.description"),
+                    level: AlertLevels.SUCCESS,
+                    message: t("console:manage.features.groups.notifications.updateGroup.success.message")
+                }));
+                handleUserUpdate(user.id);
+            }).catch(() => {
+                dispatch(addAlert({
+                    description: t("console:manage.features.groups.notifications.updateGroup.error.description"),
+                    level: AlertLevels.ERROR,
+                    message: t("console:manage.features.groups.notifications.updateGroup.error.message")
+                }));
+            }).finally(() => {
+                setDeleting(false);
+                setDeletingGroup(undefined);
+                setShowDeleteConfirmationModal(false);
+            });
+    };
+
+    /**
+     * Resolves data table columns.
+     *
+     * @returns the data table columns.
+     */
+    const resolveTableColumns = (): TableColumnInterface[] => {
+        const defaultColumns: TableColumnInterface[] = [
+            {
+                allowToggleVisibility: false,
+                dataIndex: "groupName",
+                id: "groupName",
+                key: "groupName",
+                render: (group: GroupsMemberInterface): ReactNode => {
+                    const userGroup: string[] = group?.display?.split("/");
+                    const userGroupName: string = userGroup.length === 1
+                        ? userGroup[0]
+                        : userGroup[1];
+
+                    return (
+                        <Header
+                            image
+                            as="h6"
+                            className="header-with-icon"
+                            data-componentid={ `${ componentId }-item-heading` }
+                        >
+                            <UserAvatar
+                                data-componentid="users-list-item-image"
+                                name={ group.display }
+                                size="mini"
+                                image={ user.profileUrl }
+                                spaced="right"
+                                data-suppress=""
+                            />
+                            <div>
+                                { userGroupName as ReactNode }
+                            </div>
+                        </Header>
+                    );
+                },
+                title: (
+                    <div className="pl-3">
+                        { t("user:updateUser.groups.editGroups.groupList.headers.1") }
+                    </div>
+                )
+            },
+            {
+                allowToggleVisibility: false,
+                dataIndex: "domain",
+                id: "domain",
+                key: "domain",
+                render: (group: GroupsMemberInterface): ReactNode => {
+                    const userGroup: string[] = group?.display?.split("/");
path: features/admin.users.v1/components/user-groups-list.tsx
user: login: pavinduLakshan
body: Shall we update the variable name to better match with the logic?

```suggestion
                    const groupNameSegments: string[] = group?.display?.split("/");
```
created_at: 2025-03-20T15:36:08Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,493 @@
+/**
+ * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import Box from "@oxygen-ui/react/Box/Box";
+import { AdvancedSearchWithBasicFilters } from "@wso2is/admin.core.v1/components/advanced-search-with-basic-filters";
+import { getEmptyPlaceholderIllustrations } from "@wso2is/admin.core.v1/configs/ui";
+import { UIConstants } from "@wso2is/admin.core.v1/constants/ui-constants";
+import { userstoresConfig } from "@wso2is/admin.extensions.v1";
+import { updateGroupDetails } from "@wso2is/admin.groups.v1/api/groups";
+import { GroupsMemberInterface, PatchGroupDataInterface } from "@wso2is/admin.groups.v1/models/groups";
+import {
+    AlertLevels,
+    IdentifiableComponentInterface,
+    ProfileInfoInterface
+} from "@wso2is/core/models";
+import { addAlert } from "@wso2is/core/store";
+import {
+    ConfirmationModal,
+    DataTable,
+    EmphasizedSegment,
+    EmptyPlaceholder,
+    Heading,
+    LinkButton,
+    ListLayout,
+    PrimaryButton,
+    TableActionsInterface,
+    TableColumnInterface,
+    UserAvatar
+} from "@wso2is/react-components";
+import isEmpty from "lodash-es/isEmpty";
+import React, {
+    FunctionComponent,
+    ReactElement,
+    ReactNode,
+    SyntheticEvent,
+    useEffect,
+    useState
+} from "react";
+import { useTranslation } from "react-i18next";
+import { useDispatch } from "react-redux";
+import { Dispatch } from "redux";
+import { Divider, DropdownProps, Header, Icon, Label, PaginationProps, SemanticICONS } from "semantic-ui-react";
+import "./user-roles-list.scss";
+
+interface UserGroupsEditPropsInterface extends IdentifiableComponentInterface {
+    /**
+     * User profile
+     */
+    user: ProfileInfoInterface;
+    /**
+     * Is the component loading
+     */
+    isLoading?: boolean;
+    /**
+     * Is the component in read only mode
+     */
+    isReadOnly?: boolean;
+    /**
+     * Callback to open the add new group modal
+     */
+    handleOpenAddNewGroupModal: () => void;
+    /**
+     * Handle user update callback.
+     */
+    handleUserUpdate: (userId: string) => void;
+}
+
+export const UserGroupsListTable: FunctionComponent<UserGroupsEditPropsInterface> = (
+    props: UserGroupsEditPropsInterface
+): ReactElement => {
+
+    const {
+        user,
+        isLoading,
+        isReadOnly,
+        handleOpenAddNewGroupModal,
+        handleUserUpdate,
+        "data-componentid": componentId
+    } = props;
+
+    const { t } = useTranslation();
+
+    const dispatch: Dispatch = useDispatch();
+
+    const [ searchQuery, setSearchQuery ] = useState<string>("");
+    const [ listItemLimit, setListItemLimit ] = useState<number>(UIConstants.DEFAULT_RESOURCE_LIST_ITEM_LIMIT);
+    const [ listOffset, setListOffset ] = useState<number>(0);
+    const [ paginatedGroups, setPaginatedGroups ] = useState<GroupsMemberInterface[]>(undefined);
+    const [ triggerClearQuery, setTriggerClearQuery ] = useState<boolean>(false);
+    const [ showDeleteConfirmationModal, setShowDeleteConfirmationModal ] = useState<boolean>(false);
+    const [ deletingGroup, setDeletingGroup ] = useState<GroupsMemberInterface>(undefined);
+    const [ isDeleting, setDeleting ] = useState<boolean>(false);
+
+    const userGroupsList: GroupsMemberInterface[] = user?.groups;
+
+    /**
+     * Set initial selected roles options
+     */
+    useEffect(() => {
+        setGroupsPage(0, listItemLimit, userGroupsList, searchQuery);
+    }, [ user, searchQuery ]);
+
+    /**
+     * Util method to paginate retrieved groups  list.
+     *
+     * @param offsetValue - pagination offset value.
+     * @param itemLimit - pagination item limit.
+     * @param list - Role list.
+     */
+    const setGroupsPage = (
+        offsetValue: number,
+        itemLimit: number,
+        list: GroupsMemberInterface[],
+        searchQuery?: string
+    ) => {
+        if (!list) {
+            setPaginatedGroups([]);
+
+            return;
+        }
+
+        if (!isEmpty(searchQuery)) {
+            const filteredList: GroupsMemberInterface[] = list.filter((group: GroupsMemberInterface) => {
+                return group.display.toLowerCase().includes(searchQuery.toLowerCase());
+            });
+
+            setPaginatedGroups(filteredList?.slice(offsetValue, itemLimit + offsetValue));
+
+            return;
+        }
+
+        setPaginatedGroups(list?.slice(offsetValue, itemLimit + offsetValue));
+    };
+
+
+    const handlePaginationChange = (event: React.MouseEvent<HTMLAnchorElement>, data: PaginationProps) => {
+        const offsetValue: number = (data.activePage as number - 1) * listItemLimit;
+
+        setListOffset(offsetValue);
+        setGroupsPage(offsetValue, listItemLimit, userGroupsList);
+    };
+
+    const handleItemsPerPageDropdownChange = (event: React.MouseEvent<HTMLAnchorElement>, data: DropdownProps) => {
+        setListItemLimit(data.value as number);
+        setGroupsPage(listOffset, data.value as number, userGroupsList);
+    };
+
+    const handleSearchQueryClear = (): void => {
+        setTriggerClearQuery(!triggerClearQuery);
+        setSearchQuery("");
+    };
+
+    const resolveTotalPages = (): number => {
+        return Math.ceil(userGroupsList?.length / listItemLimit);
+    };
+
+    const unassignUserFromGroup = (group: GroupsMemberInterface) => {
+        const operationData: PatchGroupDataInterface = {
+            Operations: [ {
+                "op": "remove",
+                "path": `members[value eq ${user.id}]`
+            } ],
+            schemas: [ "urn:ietf:params:scim:api:messages:2.0:PatchOp" ]
+        };
+
+        updateGroupDetails(group.value, operationData)
+            .then(() => {
+                dispatch(addAlert({
+                    description: t("console:manage.features.groups.notifications.updateGroup.success.description"),
+                    level: AlertLevels.SUCCESS,
+                    message: t("console:manage.features.groups.notifications.updateGroup.success.message")
+                }));
+                handleUserUpdate(user.id);
+            }).catch(() => {
+                dispatch(addAlert({
+                    description: t("console:manage.features.groups.notifications.updateGroup.error.description"),
+                    level: AlertLevels.ERROR,
+                    message: t("console:manage.features.groups.notifications.updateGroup.error.message")
+                }));
+            }).finally(() => {
+                setDeleting(false);
+                setDeletingGroup(undefined);
+                setShowDeleteConfirmationModal(false);
+            });
+    };
+
+    /**
+     * Resolves data table columns.
+     *
+     * @returns the data table columns.
+     */
+    const resolveTableColumns = (): TableColumnInterface[] => {
+        const defaultColumns: TableColumnInterface[] = [
+            {
+                allowToggleVisibility: false,
+                dataIndex: "groupName",
+                id: "groupName",
+                key: "groupName",
+                render: (group: GroupsMemberInterface): ReactNode => {
+                    const userGroup: string[] = group?.display?.split("/");
+                    const userGroupName: string = userGroup.length === 1
+                        ? userGroup[0]
+                        : userGroup[1];
+
+                    return (
+                        <Header
+                            image
+                            as="h6"
+                            className="header-with-icon"
+                            data-componentid={ `${ componentId }-item-heading` }
+                        >
+                            <UserAvatar
+                                data-componentid="users-list-item-image"
+                                name={ group.display }
+                                size="mini"
+                                image={ user.profileUrl }
+                                spaced="right"
+                                data-suppress=""
+                            />
+                            <div>
+                                { userGroupName as ReactNode }
+                            </div>
+                        </Header>
+                    );
+                },
+                title: (
+                    <div className="pl-3">
+                        { t("user:updateUser.groups.editGroups.groupList.headers.1") }
+                    </div>
+                )
+            },
+            {
+                allowToggleVisibility: false,
+                dataIndex: "domain",
+                id: "domain",
+                key: "domain",
+                render: (group: GroupsMemberInterface): ReactNode => {
+                    const userGroup: string[] = group?.display?.split("/");
+                    const domain: string = userGroup.length === 1
+                        ? userstoresConfig.primaryUserstoreName
+                        : userGroup[0];
+
+                    return (
+                        <Header
+                            image
+                            as="h6"
+                            className="header-with-icon"
+                            data-componentid={ `${ componentId }-item-heading` }
+                        >
+                            <Label size="mini">
+                                { domain }
+                            </Label>
+                        </Header>
+                    );
+                },
+                title: (
+                    <div className="pl-3">
+                        { t("user:updateUser.groups.editGroups.groupList.headers.0") }
+                    </div>
+                )
+            }
+        ];
+
+        defaultColumns.push(
+            {
+                allowToggleVisibility: false,
+                dataIndex: "action",
+                id: "actions",
+                key: "actions",
+                textAlign: "right",
+                title: ""
+            }
+        );
+
+        return defaultColumns;
+    };
+
+    /**
+     * Resolves data table actions.
+     *
+     * @returns Table actions.
+     */
+    const resolveTableActions = (): TableActionsInterface[] => {
+        const actions: TableActionsInterface[] = [
+            {
+                "data-componentid": `${ componentId }-user-list-item-delete-button`,
+                "data-testid": `${ componentId }-user-list-item-delete-button`,
+                hidden: (): boolean => isReadOnly,
+                icon: (): SemanticICONS =>  "trash alternate",
+                onClick: (e: SyntheticEvent, group: GroupsMemberInterface): void => {
+                    setDeletingGroup(group);
+                    setShowDeleteConfirmationModal(true);
+                },
+                popupText: (): string => t("common:delete"),
+                renderer: "semantic-icon"
+            }
+        ];
+
+        return actions;
+    };
+
+    /**
+     * Shows list placeholders.
+     *
+     * @returns Placeholders.
+     */
+    const showPlaceholders = (): ReactElement => {
+        // When the search returns empty.
path: features/admin.users.v1/components/user-groups-list.tsx
user: login: pavinduLakshan
body: The search result empty check is actually enforced at the place where `showPlaceholders` function is called, isn't it? hence this comment may not be placed here.
created_at: 2025-03-20T15:38:47Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,493 @@
+/**
+ * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import Box from "@oxygen-ui/react/Box/Box";
+import { AdvancedSearchWithBasicFilters } from "@wso2is/admin.core.v1/components/advanced-search-with-basic-filters";
+import { getEmptyPlaceholderIllustrations } from "@wso2is/admin.core.v1/configs/ui";
+import { UIConstants } from "@wso2is/admin.core.v1/constants/ui-constants";
+import { userstoresConfig } from "@wso2is/admin.extensions.v1";
+import { updateGroupDetails } from "@wso2is/admin.groups.v1/api/groups";
+import { GroupsMemberInterface, PatchGroupDataInterface } from "@wso2is/admin.groups.v1/models/groups";
+import {
+    AlertLevels,
+    IdentifiableComponentInterface,
+    ProfileInfoInterface
+} from "@wso2is/core/models";
+import { addAlert } from "@wso2is/core/store";
+import {
+    ConfirmationModal,
+    DataTable,
+    EmphasizedSegment,
+    EmptyPlaceholder,
+    Heading,
+    LinkButton,
+    ListLayout,
+    PrimaryButton,
+    TableActionsInterface,
+    TableColumnInterface,
+    UserAvatar
+} from "@wso2is/react-components";
+import isEmpty from "lodash-es/isEmpty";
+import React, {
+    FunctionComponent,
+    ReactElement,
+    ReactNode,
+    SyntheticEvent,
+    useEffect,
+    useState
+} from "react";
+import { useTranslation } from "react-i18next";
+import { useDispatch } from "react-redux";
+import { Dispatch } from "redux";
+import { Divider, DropdownProps, Header, Icon, Label, PaginationProps, SemanticICONS } from "semantic-ui-react";
+import "./user-roles-list.scss";
+
+interface UserGroupsEditPropsInterface extends IdentifiableComponentInterface {
+    /**
+     * User profile
+     */
+    user: ProfileInfoInterface;
+    /**
+     * Is the component loading
+     */
+    isLoading?: boolean;
+    /**
+     * Is the component in read only mode
+     */
+    isReadOnly?: boolean;
+    /**
+     * Callback to open the add new group modal
+     */
+    handleOpenAddNewGroupModal: () => void;
+    /**
+     * Handle user update callback.
+     */
+    handleUserUpdate: (userId: string) => void;
+}
+
+export const UserGroupsListTable: FunctionComponent<UserGroupsEditPropsInterface> = (
+    props: UserGroupsEditPropsInterface
+): ReactElement => {
+
+    const {
+        user,
+        isLoading,
+        isReadOnly,
+        handleOpenAddNewGroupModal,
+        handleUserUpdate,
+        "data-componentid": componentId
+    } = props;
+
+    const { t } = useTranslation();
+
+    const dispatch: Dispatch = useDispatch();
+
+    const [ searchQuery, setSearchQuery ] = useState<string>("");
+    const [ listItemLimit, setListItemLimit ] = useState<number>(UIConstants.DEFAULT_RESOURCE_LIST_ITEM_LIMIT);
+    const [ listOffset, setListOffset ] = useState<number>(0);
+    const [ paginatedGroups, setPaginatedGroups ] = useState<GroupsMemberInterface[]>(undefined);
+    const [ triggerClearQuery, setTriggerClearQuery ] = useState<boolean>(false);
+    const [ showDeleteConfirmationModal, setShowDeleteConfirmationModal ] = useState<boolean>(false);
+    const [ deletingGroup, setDeletingGroup ] = useState<GroupsMemberInterface>(undefined);
+    const [ isDeleting, setDeleting ] = useState<boolean>(false);
+
+    const userGroupsList: GroupsMemberInterface[] = user?.groups;
+
+    /**
+     * Set initial selected roles options
+     */
+    useEffect(() => {
+        setGroupsPage(0, listItemLimit, userGroupsList, searchQuery);
+    }, [ user, searchQuery ]);
+
+    /**
+     * Util method to paginate retrieved groups  list.
+     *
+     * @param offsetValue - pagination offset value.
+     * @param itemLimit - pagination item limit.
+     * @param list - Role list.
+     */
+    const setGroupsPage = (
+        offsetValue: number,
+        itemLimit: number,
+        list: GroupsMemberInterface[],
+        searchQuery?: string
+    ) => {
+        if (!list) {
+            setPaginatedGroups([]);
+
+            return;
+        }
+
+        if (!isEmpty(searchQuery)) {
+            const filteredList: GroupsMemberInterface[] = list.filter((group: GroupsMemberInterface) => {
+                return group.display.toLowerCase().includes(searchQuery.toLowerCase());
+            });
+
+            setPaginatedGroups(filteredList?.slice(offsetValue, itemLimit + offsetValue));
+
+            return;
+        }
+
+        setPaginatedGroups(list?.slice(offsetValue, itemLimit + offsetValue));
+    };
+
+
+    const handlePaginationChange = (event: React.MouseEvent<HTMLAnchorElement>, data: PaginationProps) => {
+        const offsetValue: number = (data.activePage as number - 1) * listItemLimit;
+
+        setListOffset(offsetValue);
+        setGroupsPage(offsetValue, listItemLimit, userGroupsList);
+    };
+
+    const handleItemsPerPageDropdownChange = (event: React.MouseEvent<HTMLAnchorElement>, data: DropdownProps) => {
+        setListItemLimit(data.value as number);
+        setGroupsPage(listOffset, data.value as number, userGroupsList);
+    };
+
+    const handleSearchQueryClear = (): void => {
+        setTriggerClearQuery(!triggerClearQuery);
+        setSearchQuery("");
+    };
+
+    const resolveTotalPages = (): number => {
+        return Math.ceil(userGroupsList?.length / listItemLimit);
+    };
+
+    const unassignUserFromGroup = (group: GroupsMemberInterface) => {
+        const operationData: PatchGroupDataInterface = {
+            Operations: [ {
+                "op": "remove",
+                "path": `members[value eq ${user.id}]`
+            } ],
+            schemas: [ "urn:ietf:params:scim:api:messages:2.0:PatchOp" ]
+        };
+
+        updateGroupDetails(group.value, operationData)
+            .then(() => {
+                dispatch(addAlert({
+                    description: t("console:manage.features.groups.notifications.updateGroup.success.description"),
+                    level: AlertLevels.SUCCESS,
+                    message: t("console:manage.features.groups.notifications.updateGroup.success.message")
+                }));
+                handleUserUpdate(user.id);
+            }).catch(() => {
+                dispatch(addAlert({
+                    description: t("console:manage.features.groups.notifications.updateGroup.error.description"),
+                    level: AlertLevels.ERROR,
+                    message: t("console:manage.features.groups.notifications.updateGroup.error.message")
+                }));
+            }).finally(() => {
+                setDeleting(false);
+                setDeletingGroup(undefined);
+                setShowDeleteConfirmationModal(false);
+            });
+    };
+
+    /**
+     * Resolves data table columns.
+     *
+     * @returns the data table columns.
+     */
+    const resolveTableColumns = (): TableColumnInterface[] => {
+        const defaultColumns: TableColumnInterface[] = [
+            {
+                allowToggleVisibility: false,
+                dataIndex: "groupName",
+                id: "groupName",
+                key: "groupName",
+                render: (group: GroupsMemberInterface): ReactNode => {
+                    const userGroup: string[] = group?.display?.split("/");
+                    const userGroupName: string = userGroup.length === 1
+                        ? userGroup[0]
+                        : userGroup[1];
+
+                    return (
+                        <Header
+                            image
+                            as="h6"
+                            className="header-with-icon"
+                            data-componentid={ `${ componentId }-item-heading` }
+                        >
+                            <UserAvatar
+                                data-componentid="users-list-item-image"
+                                name={ group.display }
+                                size="mini"
+                                image={ user.profileUrl }
+                                spaced="right"
+                                data-suppress=""
+                            />
+                            <div>
+                                { userGroupName as ReactNode }
+                            </div>
+                        </Header>
+                    );
+                },
+                title: (
+                    <div className="pl-3">
+                        { t("user:updateUser.groups.editGroups.groupList.headers.1") }
+                    </div>
+                )
+            },
+            {
+                allowToggleVisibility: false,
+                dataIndex: "domain",
+                id: "domain",
+                key: "domain",
+                render: (group: GroupsMemberInterface): ReactNode => {
+                    const userGroup: string[] = group?.display?.split("/");
+                    const domain: string = userGroup.length === 1
+                        ? userstoresConfig.primaryUserstoreName
+                        : userGroup[0];
+
+                    return (
+                        <Header
+                            image
+                            as="h6"
+                            className="header-with-icon"
+                            data-componentid={ `${ componentId }-item-heading` }
+                        >
+                            <Label size="mini">
+                                { domain }
+                            </Label>
+                        </Header>
+                    );
+                },
+                title: (
+                    <div className="pl-3">
+                        { t("user:updateUser.groups.editGroups.groupList.headers.0") }
+                    </div>
+                )
+            }
+        ];
+
+        defaultColumns.push(
+            {
+                allowToggleVisibility: false,
+                dataIndex: "action",
+                id: "actions",
+                key: "actions",
+                textAlign: "right",
+                title: ""
+            }
+        );
+
+        return defaultColumns;
+    };
+
+    /**
+     * Resolves data table actions.
+     *
+     * @returns Table actions.
+     */
+    const resolveTableActions = (): TableActionsInterface[] => {
+        const actions: TableActionsInterface[] = [
+            {
+                "data-componentid": `${ componentId }-user-list-item-delete-button`,
+                "data-testid": `${ componentId }-user-list-item-delete-button`,
+                hidden: (): boolean => isReadOnly,
+                icon: (): SemanticICONS =>  "trash alternate",
+                onClick: (e: SyntheticEvent, group: GroupsMemberInterface): void => {
+                    setDeletingGroup(group);
+                    setShowDeleteConfirmationModal(true);
+                },
+                popupText: (): string => t("common:delete"),
+                renderer: "semantic-icon"
+            }
+        ];
+
+        return actions;
+    };
+
+    /**
+     * Shows list placeholders.
+     *
+     * @returns Placeholders.
+     */
+    const showPlaceholders = (): ReactElement => {
+        // When the search returns empty.
+        if (searchQuery) {
+            return (
+                <EmptyPlaceholder
+                    action={ (
+                        <LinkButton onClick={ handleSearchQueryClear }>
+                            { t("users:usersList.search.emptyResultPlaceholder.clearButton") }
+                        </LinkButton>
+                    ) }
+                    image={ getEmptyPlaceholderIllustrations().emptySearch }
+                    imageSize="tiny"
+                    data-testid="user-mgt-empty-groups-list"
+                    title={ t("user:updateUser.groups.editGroups." +
+                        "groupList.emptyListPlaceholder.title") }
+                    subtitle={ [
+                        t("roles:list.emptyPlaceholders.search.subtitles.0",
+                            { searchQuery: searchQuery }),
+                        t("roles:list.emptyPlaceholders.search.subtitles.1")
+                    ] }
+                />
+            );
+        }
+
+        if (paginatedGroups?.length === 0) {
+            return (
+                <EmptyPlaceholder
+                    data-testid="user-mgt-empty-groups-list"
+                    title={ t("user:updateUser.groups.editGroups." +
+                        "groupList.emptyListPlaceholder.title") }
+                    subtitle={ [
+                        t("user:updateUser.groups.editGroups." +
+                                "groupList.emptyListPlaceholder.subTitle.0"),
+                        t("user:updateUser.groups.editGroups." +
+                            "groupList.emptyListPlaceholder.subTitle.1"),
+                        t("user:updateUser.groups.editGroups." +
+                            "groupList.emptyListPlaceholder.subTitle.2")
+                    ] }
+                    action={
+                        !isReadOnly && (
+                            <PrimaryButton
+                                data-testid="user-mgt-empty-groups-list-assign-group-button"
+                                onClick={ handleOpenAddNewGroupModal }
+                                loading={ isLoading }
+                                disabled={ isLoading }
+                            >
+                                <Icon name="plus"/>
+                                { t("applicationRoles:roleGroups.assignGroup") }
+                            </PrimaryButton>
+                        )
+                    }
+                    image={ getEmptyPlaceholderIllustrations().emptyList }
+                    imageSize="tiny"
+                />
+            );
+        }
+
+        return null;
+    };
+
+    return (
+        <EmphasizedSegment
+            className="list-user-roles-section"
+            data-testid="user-mgt-groups-list"
+            padded="very"
+        >
+            <Box display="flex" justifyContent="space-between" alignItems="center">
+                {
+                    (!!searchQuery || paginatedGroups?.length > 0) &&  (
+                        <div>
+                            <Heading as="h4">
+                                { t("user:updateUser.groups.editGroups.heading") }
+                            </Heading>
+                            <Heading subHeading ellipsis as="h6">
+                                { t("user:updateUser.groups.editGroups.subHeading") }
+                            </Heading>
+                        </div>
+                    )
+                }
+                { !isReadOnly && (!!searchQuery || paginatedGroups?.length > 0) && (
+                    <PrimaryButton
+                        data-testid="user-mgt-groups-list-update-button"
+                        onClick={ handleOpenAddNewGroupModal }
+                    >
+                        <Icon name="plus"/>
+                        { t("applicationRoles:roleGroups.assignGroup") }
+                    </PrimaryButton>
+                ) }
+            </Box>
+            <Divider hidden/>
+            <ListLayout
+                advancedSearch={ (
+                    <AdvancedSearchWithBasicFilters
+                        data-testid="group-mgt-groups-list-advanced-search"
+                        onFilter={ (query: string) => setSearchQuery(query?.trim()) }
+                        disableSearchFilterDropdown
+                        filterAttributeOptions={ [] }
+                        placeholder={ t("console:manage.features.groups.advancedSearch.placeholder") }
+                        defaultSearchAttribute={ "" }
+                        defaultSearchOperator={ "" }
path: features/admin.users.v1/components/user-groups-list.tsx
user: login: pavinduLakshan
body: ```suggestion
                        defaultSearchAttribute=""
                        defaultSearchOperator=""
```
created_at: 2025-03-20T15:40:16Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,493 @@
+/**
+ * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import Box from "@oxygen-ui/react/Box/Box";
+import { AdvancedSearchWithBasicFilters } from "@wso2is/admin.core.v1/components/advanced-search-with-basic-filters";
+import { getEmptyPlaceholderIllustrations } from "@wso2is/admin.core.v1/configs/ui";
+import { UIConstants } from "@wso2is/admin.core.v1/constants/ui-constants";
+import { userstoresConfig } from "@wso2is/admin.extensions.v1";
+import { updateGroupDetails } from "@wso2is/admin.groups.v1/api/groups";
+import { GroupsMemberInterface, PatchGroupDataInterface } from "@wso2is/admin.groups.v1/models/groups";
+import {
+    AlertLevels,
+    IdentifiableComponentInterface,
+    ProfileInfoInterface
+} from "@wso2is/core/models";
+import { addAlert } from "@wso2is/core/store";
+import {
+    ConfirmationModal,
+    DataTable,
+    EmphasizedSegment,
+    EmptyPlaceholder,
+    Heading,
+    LinkButton,
+    ListLayout,
+    PrimaryButton,
+    TableActionsInterface,
+    TableColumnInterface,
+    UserAvatar
+} from "@wso2is/react-components";
+import isEmpty from "lodash-es/isEmpty";
+import React, {
+    FunctionComponent,
+    ReactElement,
+    ReactNode,
+    SyntheticEvent,
+    useEffect,
+    useState
+} from "react";
+import { useTranslation } from "react-i18next";
+import { useDispatch } from "react-redux";
+import { Dispatch } from "redux";
+import { Divider, DropdownProps, Header, Icon, Label, PaginationProps, SemanticICONS } from "semantic-ui-react";
+import "./user-roles-list.scss";
+
+interface UserGroupsEditPropsInterface extends IdentifiableComponentInterface {
+    /**
+     * User profile
+     */
+    user: ProfileInfoInterface;
+    /**
+     * Is the component loading
+     */
+    isLoading?: boolean;
+    /**
+     * Is the component in read only mode
+     */
+    isReadOnly?: boolean;
+    /**
+     * Callback to open the add new group modal
+     */
+    handleOpenAddNewGroupModal: () => void;
+    /**
+     * Handle user update callback.
+     */
+    handleUserUpdate: (userId: string) => void;
+}
+
+export const UserGroupsListTable: FunctionComponent<UserGroupsEditPropsInterface> = (
+    props: UserGroupsEditPropsInterface
+): ReactElement => {
+
+    const {
+        user,
+        isLoading,
+        isReadOnly,
+        handleOpenAddNewGroupModal,
+        handleUserUpdate,
+        "data-componentid": componentId
+    } = props;
+
+    const { t } = useTranslation();
+
+    const dispatch: Dispatch = useDispatch();
+
+    const [ searchQuery, setSearchQuery ] = useState<string>("");
+    const [ listItemLimit, setListItemLimit ] = useState<number>(UIConstants.DEFAULT_RESOURCE_LIST_ITEM_LIMIT);
+    const [ listOffset, setListOffset ] = useState<number>(0);
+    const [ paginatedGroups, setPaginatedGroups ] = useState<GroupsMemberInterface[]>(undefined);
+    const [ triggerClearQuery, setTriggerClearQuery ] = useState<boolean>(false);
+    const [ showDeleteConfirmationModal, setShowDeleteConfirmationModal ] = useState<boolean>(false);
+    const [ deletingGroup, setDeletingGroup ] = useState<GroupsMemberInterface>(undefined);
+    const [ isDeleting, setDeleting ] = useState<boolean>(false);
+
+    const userGroupsList: GroupsMemberInterface[] = user?.groups;
+
+    /**
+     * Set initial selected roles options
+     */
+    useEffect(() => {
+        setGroupsPage(0, listItemLimit, userGroupsList, searchQuery);
+    }, [ user, searchQuery ]);
+
+    /**
+     * Util method to paginate retrieved groups  list.
+     *
+     * @param offsetValue - pagination offset value.
+     * @param itemLimit - pagination item limit.
+     * @param list - Role list.
+     */
+    const setGroupsPage = (
+        offsetValue: number,
+        itemLimit: number,
+        list: GroupsMemberInterface[],
+        searchQuery?: string
+    ) => {
+        if (!list) {
+            setPaginatedGroups([]);
+
+            return;
+        }
+
+        if (!isEmpty(searchQuery)) {
+            const filteredList: GroupsMemberInterface[] = list.filter((group: GroupsMemberInterface) => {
+                return group.display.toLowerCase().includes(searchQuery.toLowerCase());
+            });
+
+            setPaginatedGroups(filteredList?.slice(offsetValue, itemLimit + offsetValue));
+
+            return;
+        }
+
+        setPaginatedGroups(list?.slice(offsetValue, itemLimit + offsetValue));
+    };
+
+
+    const handlePaginationChange = (event: React.MouseEvent<HTMLAnchorElement>, data: PaginationProps) => {
+        const offsetValue: number = (data.activePage as number - 1) * listItemLimit;
+
+        setListOffset(offsetValue);
+        setGroupsPage(offsetValue, listItemLimit, userGroupsList);
+    };
+
+    const handleItemsPerPageDropdownChange = (event: React.MouseEvent<HTMLAnchorElement>, data: DropdownProps) => {
+        setListItemLimit(data.value as number);
+        setGroupsPage(listOffset, data.value as number, userGroupsList);
+    };
+
+    const handleSearchQueryClear = (): void => {
+        setTriggerClearQuery(!triggerClearQuery);
+        setSearchQuery("");
+    };
+
+    const resolveTotalPages = (): number => {
+        return Math.ceil(userGroupsList?.length / listItemLimit);
+    };
+
+    const unassignUserFromGroup = (group: GroupsMemberInterface) => {
+        const operationData: PatchGroupDataInterface = {
+            Operations: [ {
+                "op": "remove",
+                "path": `members[value eq ${user.id}]`
+            } ],
+            schemas: [ "urn:ietf:params:scim:api:messages:2.0:PatchOp" ]
+        };
+
+        updateGroupDetails(group.value, operationData)
+            .then(() => {
+                dispatch(addAlert({
+                    description: t("console:manage.features.groups.notifications.updateGroup.success.description"),
+                    level: AlertLevels.SUCCESS,
+                    message: t("console:manage.features.groups.notifications.updateGroup.success.message")
+                }));
+                handleUserUpdate(user.id);
+            }).catch(() => {
+                dispatch(addAlert({
+                    description: t("console:manage.features.groups.notifications.updateGroup.error.description"),
+                    level: AlertLevels.ERROR,
+                    message: t("console:manage.features.groups.notifications.updateGroup.error.message")
+                }));
+            }).finally(() => {
+                setDeleting(false);
+                setDeletingGroup(undefined);
+                setShowDeleteConfirmationModal(false);
+            });
+    };
+
+    /**
+     * Resolves data table columns.
+     *
+     * @returns the data table columns.
+     */
+    const resolveTableColumns = (): TableColumnInterface[] => {
+        const defaultColumns: TableColumnInterface[] = [
+            {
+                allowToggleVisibility: false,
+                dataIndex: "groupName",
+                id: "groupName",
+                key: "groupName",
+                render: (group: GroupsMemberInterface): ReactNode => {
+                    const userGroup: string[] = group?.display?.split("/");
+                    const userGroupName: string = userGroup.length === 1
+                        ? userGroup[0]
+                        : userGroup[1];
+
+                    return (
+                        <Header
+                            image
+                            as="h6"
+                            className="header-with-icon"
+                            data-componentid={ `${ componentId }-item-heading` }
+                        >
+                            <UserAvatar
+                                data-componentid="users-list-item-image"
+                                name={ group.display }
+                                size="mini"
+                                image={ user.profileUrl }
+                                spaced="right"
+                                data-suppress=""
+                            />
+                            <div>
+                                { userGroupName as ReactNode }
+                            </div>
+                        </Header>
+                    );
+                },
+                title: (
+                    <div className="pl-3">
+                        { t("user:updateUser.groups.editGroups.groupList.headers.1") }
+                    </div>
+                )
+            },
+            {
+                allowToggleVisibility: false,
+                dataIndex: "domain",
+                id: "domain",
+                key: "domain",
+                render: (group: GroupsMemberInterface): ReactNode => {
+                    const userGroup: string[] = group?.display?.split("/");
+                    const domain: string = userGroup.length === 1
+                        ? userstoresConfig.primaryUserstoreName
+                        : userGroup[0];
+
+                    return (
+                        <Header
+                            image
+                            as="h6"
+                            className="header-with-icon"
+                            data-componentid={ `${ componentId }-item-heading` }
+                        >
+                            <Label size="mini">
+                                { domain }
+                            </Label>
+                        </Header>
+                    );
+                },
+                title: (
+                    <div className="pl-3">
+                        { t("user:updateUser.groups.editGroups.groupList.headers.0") }
+                    </div>
+                )
+            }
+        ];
+
+        defaultColumns.push(
+            {
+                allowToggleVisibility: false,
+                dataIndex: "action",
+                id: "actions",
+                key: "actions",
+                textAlign: "right",
+                title: ""
+            }
+        );
+
+        return defaultColumns;
+    };
+
+    /**
+     * Resolves data table actions.
+     *
+     * @returns Table actions.
+     */
+    const resolveTableActions = (): TableActionsInterface[] => {
+        const actions: TableActionsInterface[] = [
+            {
+                "data-componentid": `${ componentId }-user-list-item-delete-button`,
+                "data-testid": `${ componentId }-user-list-item-delete-button`,
+                hidden: (): boolean => isReadOnly,
+                icon: (): SemanticICONS =>  "trash alternate",
+                onClick: (e: SyntheticEvent, group: GroupsMemberInterface): void => {
+                    setDeletingGroup(group);
+                    setShowDeleteConfirmationModal(true);
+                },
+                popupText: (): string => t("common:delete"),
+                renderer: "semantic-icon"
+            }
+        ];
+
+        return actions;
+    };
+
+    /**
+     * Shows list placeholders.
+     *
+     * @returns Placeholders.
+     */
+    const showPlaceholders = (): ReactElement => {
+        // When the search returns empty.
+        if (searchQuery) {
+            return (
+                <EmptyPlaceholder
+                    action={ (
+                        <LinkButton onClick={ handleSearchQueryClear }>
+                            { t("users:usersList.search.emptyResultPlaceholder.clearButton") }
+                        </LinkButton>
+                    ) }
+                    image={ getEmptyPlaceholderIllustrations().emptySearch }
+                    imageSize="tiny"
+                    data-testid="user-mgt-empty-groups-list"
+                    title={ t("user:updateUser.groups.editGroups." +
+                        "groupList.emptyListPlaceholder.title") }
+                    subtitle={ [
+                        t("roles:list.emptyPlaceholders.search.subtitles.0",
+                            { searchQuery: searchQuery }),
+                        t("roles:list.emptyPlaceholders.search.subtitles.1")
+                    ] }
+                />
+            );
+        }
+
+        if (paginatedGroups?.length === 0) {
+            return (
+                <EmptyPlaceholder
+                    data-testid="user-mgt-empty-groups-list"
+                    title={ t("user:updateUser.groups.editGroups." +
+                        "groupList.emptyListPlaceholder.title") }
+                    subtitle={ [
+                        t("user:updateUser.groups.editGroups." +
+                                "groupList.emptyListPlaceholder.subTitle.0"),
+                        t("user:updateUser.groups.editGroups." +
+                            "groupList.emptyListPlaceholder.subTitle.1"),
+                        t("user:updateUser.groups.editGroups." +
+                            "groupList.emptyListPlaceholder.subTitle.2")
+                    ] }
+                    action={
+                        !isReadOnly && (
+                            <PrimaryButton
+                                data-testid="user-mgt-empty-groups-list-assign-group-button"
+                                onClick={ handleOpenAddNewGroupModal }
+                                loading={ isLoading }
+                                disabled={ isLoading }
+                            >
+                                <Icon name="plus"/>
+                                { t("applicationRoles:roleGroups.assignGroup") }
+                            </PrimaryButton>
+                        )
+                    }
+                    image={ getEmptyPlaceholderIllustrations().emptyList }
+                    imageSize="tiny"
+                />
+            );
+        }
+
+        return null;
+    };
+
+    return (
+        <EmphasizedSegment
+            className="list-user-roles-section"
+            data-testid="user-mgt-groups-list"
+            padded="very"
+        >
+            <Box display="flex" justifyContent="space-between" alignItems="center">
+                {
+                    (!!searchQuery || paginatedGroups?.length > 0) &&  (
+                        <div>
+                            <Heading as="h4">
+                                { t("user:updateUser.groups.editGroups.heading") }
+                            </Heading>
+                            <Heading subHeading ellipsis as="h6">
+                                { t("user:updateUser.groups.editGroups.subHeading") }
+                            </Heading>
+                        </div>
+                    )
+                }
+                { !isReadOnly && (!!searchQuery || paginatedGroups?.length > 0) && (
+                    <PrimaryButton
+                        data-testid="user-mgt-groups-list-update-button"
+                        onClick={ handleOpenAddNewGroupModal }
+                    >
+                        <Icon name="plus"/>
+                        { t("applicationRoles:roleGroups.assignGroup") }
+                    </PrimaryButton>
+                ) }
+            </Box>
+            <Divider hidden/>
+            <ListLayout
+                advancedSearch={ (
+                    <AdvancedSearchWithBasicFilters
+                        data-testid="group-mgt-groups-list-advanced-search"
+                        onFilter={ (query: string) => setSearchQuery(query?.trim()) }
+                        disableSearchFilterDropdown
+                        filterAttributeOptions={ [] }
+                        placeholder={ t("console:manage.features.groups.advancedSearch.placeholder") }
+                        defaultSearchAttribute={ "" }
+                        defaultSearchOperator={ "" }
+                        triggerClearQuery={ triggerClearQuery }
+                    />
+                ) }
+                currentListSize={ paginatedGroups?.length }
+                listItemLimit={ listItemLimit }
+                onItemsPerPageDropdownChange={ handleItemsPerPageDropdownChange }
+                data-componentid={ `${ componentId }-user-groups-list-layout` }
+                data-testid={ `${ componentId }-user-groups-list-layout` }
+                onPageChange={ handlePaginationChange }
+                showPagination={ true }
+                totalPages={ resolveTotalPages() }
+                totalListSize={ userGroupsList?.length }
+                showPaginationPageLimit={ !isReadOnly }
+                showTopActionPanel={ (!!searchQuery || userGroupsList?.length > 0) }
+            >
+                <DataTable<GroupsMemberInterface>
+                    isLoading={ isLoading }
+                    loadingStateOptions={ {
+                        count: UIConstants.DEFAULT_RESOURCE_LIST_ITEM_LIMIT,
+                        imageType: "circular"
+                    } }
+                    actions={ resolveTableActions() }
+                    columns={ resolveTableColumns() }
+                    data={ paginatedGroups }
+                    onRowClick={ () =>  null }
path: features/admin.users.v1/components/user-groups-list.tsx
user: login: pavinduLakshan
body: Hope this is intentional
created_at: 2025-03-20T15:41:14Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,493 @@
+/**
+ * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import Box from "@oxygen-ui/react/Box/Box";
+import { AdvancedSearchWithBasicFilters } from "@wso2is/admin.core.v1/components/advanced-search-with-basic-filters";
+import { getEmptyPlaceholderIllustrations } from "@wso2is/admin.core.v1/configs/ui";
+import { UIConstants } from "@wso2is/admin.core.v1/constants/ui-constants";
+import { userstoresConfig } from "@wso2is/admin.extensions.v1";
+import { updateGroupDetails } from "@wso2is/admin.groups.v1/api/groups";
+import { GroupsMemberInterface, PatchGroupDataInterface } from "@wso2is/admin.groups.v1/models/groups";
+import {
+    AlertLevels,
+    IdentifiableComponentInterface,
+    ProfileInfoInterface
+} from "@wso2is/core/models";
+import { addAlert } from "@wso2is/core/store";
+import {
+    ConfirmationModal,
+    DataTable,
+    EmphasizedSegment,
+    EmptyPlaceholder,
+    Heading,
+    LinkButton,
+    ListLayout,
+    PrimaryButton,
+    TableActionsInterface,
+    TableColumnInterface,
+    UserAvatar
+} from "@wso2is/react-components";
+import isEmpty from "lodash-es/isEmpty";
+import React, {
+    FunctionComponent,
+    ReactElement,
+    ReactNode,
+    SyntheticEvent,
+    useEffect,
+    useState
+} from "react";
+import { useTranslation } from "react-i18next";
+import { useDispatch } from "react-redux";
+import { Dispatch } from "redux";
+import { Divider, DropdownProps, Header, Icon, Label, PaginationProps, SemanticICONS } from "semantic-ui-react";
+import "./user-roles-list.scss";
+
+interface UserGroupsEditPropsInterface extends IdentifiableComponentInterface {
+    /**
+     * User profile
+     */
+    user: ProfileInfoInterface;
+    /**
+     * Is the component loading
+     */
+    isLoading?: boolean;
+    /**
+     * Is the component in read only mode
+     */
+    isReadOnly?: boolean;
+    /**
+     * Callback to open the add new group modal
+     */
+    handleOpenAddNewGroupModal: () => void;
+    /**
+     * Handle user update callback.
+     */
+    handleUserUpdate: (userId: string) => void;
+}
+
+export const UserGroupsListTable: FunctionComponent<UserGroupsEditPropsInterface> = (
+    props: UserGroupsEditPropsInterface
+): ReactElement => {
+
+    const {
+        user,
+        isLoading,
+        isReadOnly,
+        handleOpenAddNewGroupModal,
+        handleUserUpdate,
+        "data-componentid": componentId
+    } = props;
+
+    const { t } = useTranslation();
+
+    const dispatch: Dispatch = useDispatch();
+
+    const [ searchQuery, setSearchQuery ] = useState<string>("");
+    const [ listItemLimit, setListItemLimit ] = useState<number>(UIConstants.DEFAULT_RESOURCE_LIST_ITEM_LIMIT);
+    const [ listOffset, setListOffset ] = useState<number>(0);
+    const [ paginatedGroups, setPaginatedGroups ] = useState<GroupsMemberInterface[]>(undefined);
+    const [ triggerClearQuery, setTriggerClearQuery ] = useState<boolean>(false);
+    const [ showDeleteConfirmationModal, setShowDeleteConfirmationModal ] = useState<boolean>(false);
+    const [ deletingGroup, setDeletingGroup ] = useState<GroupsMemberInterface>(undefined);
+    const [ isDeleting, setDeleting ] = useState<boolean>(false);
+
+    const userGroupsList: GroupsMemberInterface[] = user?.groups;
+
+    /**
+     * Set initial selected roles options
+     */
+    useEffect(() => {
+        setGroupsPage(0, listItemLimit, userGroupsList, searchQuery);
+    }, [ user, searchQuery ]);
+
+    /**
+     * Util method to paginate retrieved groups  list.
+     *
+     * @param offsetValue - pagination offset value.
+     * @param itemLimit - pagination item limit.
+     * @param list - Role list.
+     */
+    const setGroupsPage = (
+        offsetValue: number,
+        itemLimit: number,
+        list: GroupsMemberInterface[],
+        searchQuery?: string
+    ) => {
+        if (!list) {
+            setPaginatedGroups([]);
+
+            return;
+        }
+
+        if (!isEmpty(searchQuery)) {
+            const filteredList: GroupsMemberInterface[] = list.filter((group: GroupsMemberInterface) => {
+                return group.display.toLowerCase().includes(searchQuery.toLowerCase());
+            });
+
+            setPaginatedGroups(filteredList?.slice(offsetValue, itemLimit + offsetValue));
+
+            return;
+        }
+
+        setPaginatedGroups(list?.slice(offsetValue, itemLimit + offsetValue));
+    };
+
+
+    const handlePaginationChange = (event: React.MouseEvent<HTMLAnchorElement>, data: PaginationProps) => {
+        const offsetValue: number = (data.activePage as number - 1) * listItemLimit;
+
+        setListOffset(offsetValue);
+        setGroupsPage(offsetValue, listItemLimit, userGroupsList);
+    };
+
+    const handleItemsPerPageDropdownChange = (event: React.MouseEvent<HTMLAnchorElement>, data: DropdownProps) => {
+        setListItemLimit(data.value as number);
+        setGroupsPage(listOffset, data.value as number, userGroupsList);
+    };
+
+    const handleSearchQueryClear = (): void => {
+        setTriggerClearQuery(!triggerClearQuery);
+        setSearchQuery("");
+    };
+
+    const resolveTotalPages = (): number => {
+        return Math.ceil(userGroupsList?.length / listItemLimit);
+    };
+
+    const unassignUserFromGroup = (group: GroupsMemberInterface) => {
+        const operationData: PatchGroupDataInterface = {
+            Operations: [ {
+                "op": "remove",
+                "path": `members[value eq ${user.id}]`
+            } ],
+            schemas: [ "urn:ietf:params:scim:api:messages:2.0:PatchOp" ]
+        };
+
+        updateGroupDetails(group.value, operationData)
+            .then(() => {
+                dispatch(addAlert({
+                    description: t("console:manage.features.groups.notifications.updateGroup.success.description"),
+                    level: AlertLevels.SUCCESS,
+                    message: t("console:manage.features.groups.notifications.updateGroup.success.message")
+                }));
+                handleUserUpdate(user.id);
+            }).catch(() => {
+                dispatch(addAlert({
+                    description: t("console:manage.features.groups.notifications.updateGroup.error.description"),
+                    level: AlertLevels.ERROR,
+                    message: t("console:manage.features.groups.notifications.updateGroup.error.message")
+                }));
+            }).finally(() => {
+                setDeleting(false);
+                setDeletingGroup(undefined);
+                setShowDeleteConfirmationModal(false);
+            });
+    };
+
+    /**
+     * Resolves data table columns.
+     *
+     * @returns the data table columns.
+     */
+    const resolveTableColumns = (): TableColumnInterface[] => {
+        const defaultColumns: TableColumnInterface[] = [
+            {
+                allowToggleVisibility: false,
+                dataIndex: "groupName",
+                id: "groupName",
+                key: "groupName",
+                render: (group: GroupsMemberInterface): ReactNode => {
+                    const userGroup: string[] = group?.display?.split("/");
+                    const userGroupName: string = userGroup.length === 1
+                        ? userGroup[0]
+                        : userGroup[1];
+
+                    return (
+                        <Header
+                            image
+                            as="h6"
+                            className="header-with-icon"
+                            data-componentid={ `${ componentId }-item-heading` }
+                        >
+                            <UserAvatar
+                                data-componentid="users-list-item-image"
+                                name={ group.display }
+                                size="mini"
+                                image={ user.profileUrl }
+                                spaced="right"
+                                data-suppress=""
+                            />
+                            <div>
+                                { userGroupName as ReactNode }
+                            </div>
+                        </Header>
+                    );
+                },
+                title: (
+                    <div className="pl-3">
+                        { t("user:updateUser.groups.editGroups.groupList.headers.1") }
+                    </div>
+                )
+            },
+            {
+                allowToggleVisibility: false,
+                dataIndex: "domain",
+                id: "domain",
+                key: "domain",
+                render: (group: GroupsMemberInterface): ReactNode => {
+                    const userGroup: string[] = group?.display?.split("/");
+                    const domain: string = userGroup.length === 1
+                        ? userstoresConfig.primaryUserstoreName
+                        : userGroup[0];
+
+                    return (
+                        <Header
+                            image
+                            as="h6"
+                            className="header-with-icon"
+                            data-componentid={ `${ componentId }-item-heading` }
+                        >
+                            <Label size="mini">
+                                { domain }
+                            </Label>
+                        </Header>
+                    );
+                },
+                title: (
+                    <div className="pl-3">
+                        { t("user:updateUser.groups.editGroups.groupList.headers.0") }
+                    </div>
+                )
+            }
+        ];
+
+        defaultColumns.push(
+            {
+                allowToggleVisibility: false,
+                dataIndex: "action",
+                id: "actions",
+                key: "actions",
+                textAlign: "right",
+                title: ""
+            }
+        );
+
+        return defaultColumns;
+    };
+
+    /**
+     * Resolves data table actions.
+     *
+     * @returns Table actions.
+     */
+    const resolveTableActions = (): TableActionsInterface[] => {
+        const actions: TableActionsInterface[] = [
+            {
+                "data-componentid": `${ componentId }-user-list-item-delete-button`,
+                "data-testid": `${ componentId }-user-list-item-delete-button`,
+                hidden: (): boolean => isReadOnly,
+                icon: (): SemanticICONS =>  "trash alternate",
+                onClick: (e: SyntheticEvent, group: GroupsMemberInterface): void => {
+                    setDeletingGroup(group);
+                    setShowDeleteConfirmationModal(true);
+                },
+                popupText: (): string => t("common:delete"),
+                renderer: "semantic-icon"
+            }
+        ];
+
+        return actions;
+    };
+
+    /**
+     * Shows list placeholders.
+     *
+     * @returns Placeholders.
+     */
+    const showPlaceholders = (): ReactElement => {
+        // When the search returns empty.
+        if (searchQuery) {
+            return (
+                <EmptyPlaceholder
+                    action={ (
+                        <LinkButton onClick={ handleSearchQueryClear }>
+                            { t("users:usersList.search.emptyResultPlaceholder.clearButton") }
+                        </LinkButton>
+                    ) }
+                    image={ getEmptyPlaceholderIllustrations().emptySearch }
+                    imageSize="tiny"
+                    data-testid="user-mgt-empty-groups-list"
+                    title={ t("user:updateUser.groups.editGroups." +
+                        "groupList.emptyListPlaceholder.title") }
+                    subtitle={ [
+                        t("roles:list.emptyPlaceholders.search.subtitles.0",
+                            { searchQuery: searchQuery }),
+                        t("roles:list.emptyPlaceholders.search.subtitles.1")
+                    ] }
+                />
+            );
+        }
+
+        if (paginatedGroups?.length === 0) {
+            return (
+                <EmptyPlaceholder
+                    data-testid="user-mgt-empty-groups-list"
+                    title={ t("user:updateUser.groups.editGroups." +
+                        "groupList.emptyListPlaceholder.title") }
+                    subtitle={ [
+                        t("user:updateUser.groups.editGroups." +
+                                "groupList.emptyListPlaceholder.subTitle.0"),
+                        t("user:updateUser.groups.editGroups." +
+                            "groupList.emptyListPlaceholder.subTitle.1"),
+                        t("user:updateUser.groups.editGroups." +
+                            "groupList.emptyListPlaceholder.subTitle.2")
+                    ] }
+                    action={
+                        !isReadOnly && (
+                            <PrimaryButton
+                                data-testid="user-mgt-empty-groups-list-assign-group-button"
+                                onClick={ handleOpenAddNewGroupModal }
+                                loading={ isLoading }
+                                disabled={ isLoading }
+                            >
+                                <Icon name="plus"/>
+                                { t("applicationRoles:roleGroups.assignGroup") }
+                            </PrimaryButton>
+                        )
+                    }
+                    image={ getEmptyPlaceholderIllustrations().emptyList }
+                    imageSize="tiny"
+                />
+            );
+        }
+
+        return null;
+    };
+
+    return (
+        <EmphasizedSegment
+            className="list-user-roles-section"
+            data-testid="user-mgt-groups-list"
+            padded="very"
+        >
+            <Box display="flex" justifyContent="space-between" alignItems="center">
+                {
+                    (!!searchQuery || paginatedGroups?.length > 0) &&  (
+                        <div>
+                            <Heading as="h4">
+                                { t("user:updateUser.groups.editGroups.heading") }
+                            </Heading>
+                            <Heading subHeading ellipsis as="h6">
+                                { t("user:updateUser.groups.editGroups.subHeading") }
+                            </Heading>
+                        </div>
+                    )
+                }
+                { !isReadOnly && (!!searchQuery || paginatedGroups?.length > 0) && (
+                    <PrimaryButton
+                        data-testid="user-mgt-groups-list-update-button"
+                        onClick={ handleOpenAddNewGroupModal }
+                    >
+                        <Icon name="plus"/>
+                        { t("applicationRoles:roleGroups.assignGroup") }
+                    </PrimaryButton>
+                ) }
+            </Box>
+            <Divider hidden/>
+            <ListLayout
+                advancedSearch={ (
+                    <AdvancedSearchWithBasicFilters
+                        data-testid="group-mgt-groups-list-advanced-search"
+                        onFilter={ (query: string) => setSearchQuery(query?.trim()) }
+                        disableSearchFilterDropdown
+                        filterAttributeOptions={ [] }
+                        placeholder={ t("console:manage.features.groups.advancedSearch.placeholder") }
+                        defaultSearchAttribute={ "" }
+                        defaultSearchOperator={ "" }
+                        triggerClearQuery={ triggerClearQuery }
+                    />
+                ) }
+                currentListSize={ paginatedGroups?.length }
+                listItemLimit={ listItemLimit }
+                onItemsPerPageDropdownChange={ handleItemsPerPageDropdownChange }
+                data-componentid={ `${ componentId }-user-groups-list-layout` }
+                data-testid={ `${ componentId }-user-groups-list-layout` }
+                onPageChange={ handlePaginationChange }
+                showPagination={ true }
+                totalPages={ resolveTotalPages() }
+                totalListSize={ userGroupsList?.length }
+                showPaginationPageLimit={ !isReadOnly }
+                showTopActionPanel={ (!!searchQuery || userGroupsList?.length > 0) }
+            >
+                <DataTable<GroupsMemberInterface>
+                    isLoading={ isLoading }
+                    loadingStateOptions={ {
+                        count: UIConstants.DEFAULT_RESOURCE_LIST_ITEM_LIMIT,
+                        imageType: "circular"
+                    } }
+                    actions={ resolveTableActions() }
+                    columns={ resolveTableColumns() }
+                    data={ paginatedGroups }
+                    onRowClick={ () =>  null }
+                    placeholders={ showPlaceholders() }
+                    selectable={ false }
+                    showHeader={ true }
+                    data-testid={ componentId }
+                />
+            </ListLayout>
+            <ConfirmationModal
+                primaryActionLoading={ isDeleting }
+                data-testid={ `${ componentId }-confirmation-modal` }
+                data-componentid={ `${ componentId }-confirmation-modal` }
+                onClose={ (): void => setShowDeleteConfirmationModal(false) }
+                type="negative"
+                open={ showDeleteConfirmationModal }
+                primaryAction="Confirm"
+                secondaryAction="Cancel"
path: features/admin.users.v1/components/user-groups-list.tsx
user: login: pavinduLakshan
body: Shall we use i18n here?

```suggestion
                primaryAction={ t("common:confirm") }
                secondaryAction={ t("common:cancel") }
```
created_at: 2025-03-20T15:42:42Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,493 @@
+/**
+ * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import Box from "@oxygen-ui/react/Box/Box";
+import { AdvancedSearchWithBasicFilters } from "@wso2is/admin.core.v1/components/advanced-search-with-basic-filters";
+import { getEmptyPlaceholderIllustrations } from "@wso2is/admin.core.v1/configs/ui";
+import { UIConstants } from "@wso2is/admin.core.v1/constants/ui-constants";
+import { userstoresConfig } from "@wso2is/admin.extensions.v1";
+import { updateGroupDetails } from "@wso2is/admin.groups.v1/api/groups";
+import { GroupsMemberInterface, PatchGroupDataInterface } from "@wso2is/admin.groups.v1/models/groups";
+import {
+    AlertLevels,
+    IdentifiableComponentInterface,
+    ProfileInfoInterface
+} from "@wso2is/core/models";
+import { addAlert } from "@wso2is/core/store";
+import {
+    ConfirmationModal,
+    DataTable,
+    EmphasizedSegment,
+    EmptyPlaceholder,
+    Heading,
+    LinkButton,
+    ListLayout,
+    PrimaryButton,
+    TableActionsInterface,
+    TableColumnInterface,
+    UserAvatar
+} from "@wso2is/react-components";
+import isEmpty from "lodash-es/isEmpty";
+import React, {
+    FunctionComponent,
+    ReactElement,
+    ReactNode,
+    SyntheticEvent,
+    useEffect,
+    useState
+} from "react";
+import { useTranslation } from "react-i18next";
+import { useDispatch } from "react-redux";
+import { Dispatch } from "redux";
+import { Divider, DropdownProps, Header, Icon, Label, PaginationProps, SemanticICONS } from "semantic-ui-react";
+import "./user-roles-list.scss";
+
+interface UserGroupsEditPropsInterface extends IdentifiableComponentInterface {
+    /**
+     * User profile
+     */
+    user: ProfileInfoInterface;
+    /**
+     * Is the component loading
+     */
+    isLoading?: boolean;
+    /**
+     * Is the component in read only mode
+     */
+    isReadOnly?: boolean;
+    /**
+     * Callback to open the add new group modal
+     */
+    handleOpenAddNewGroupModal: () => void;
+    /**
+     * Handle user update callback.
+     */
+    handleUserUpdate: (userId: string) => void;
+}
+
+export const UserGroupsListTable: FunctionComponent<UserGroupsEditPropsInterface> = (
+    props: UserGroupsEditPropsInterface
+): ReactElement => {
+
+    const {
+        user,
+        isLoading,
+        isReadOnly,
+        handleOpenAddNewGroupModal,
+        handleUserUpdate,
+        "data-componentid": componentId
+    } = props;
+
+    const { t } = useTranslation();
+
+    const dispatch: Dispatch = useDispatch();
+
+    const [ searchQuery, setSearchQuery ] = useState<string>("");
+    const [ listItemLimit, setListItemLimit ] = useState<number>(UIConstants.DEFAULT_RESOURCE_LIST_ITEM_LIMIT);
+    const [ listOffset, setListOffset ] = useState<number>(0);
+    const [ paginatedGroups, setPaginatedGroups ] = useState<GroupsMemberInterface[]>(undefined);
+    const [ triggerClearQuery, setTriggerClearQuery ] = useState<boolean>(false);
+    const [ showDeleteConfirmationModal, setShowDeleteConfirmationModal ] = useState<boolean>(false);
+    const [ deletingGroup, setDeletingGroup ] = useState<GroupsMemberInterface>(undefined);
+    const [ isDeleting, setDeleting ] = useState<boolean>(false);
+
+    const userGroupsList: GroupsMemberInterface[] = user?.groups;
+
+    /**
+     * Set initial selected roles options
+     */
+    useEffect(() => {
+        setGroupsPage(0, listItemLimit, userGroupsList, searchQuery);
+    }, [ user, searchQuery ]);
+
+    /**
+     * Util method to paginate retrieved groups  list.
+     *
+     * @param offsetValue - pagination offset value.
+     * @param itemLimit - pagination item limit.
+     * @param list - Role list.
+     */
+    const setGroupsPage = (
+        offsetValue: number,
+        itemLimit: number,
+        list: GroupsMemberInterface[],
+        searchQuery?: string
+    ) => {
+        if (!list) {
+            setPaginatedGroups([]);
+
+            return;
+        }
+
+        if (!isEmpty(searchQuery)) {
+            const filteredList: GroupsMemberInterface[] = list.filter((group: GroupsMemberInterface) => {
+                return group.display.toLowerCase().includes(searchQuery.toLowerCase());
+            });
+
+            setPaginatedGroups(filteredList?.slice(offsetValue, itemLimit + offsetValue));
+
+            return;
+        }
+
+        setPaginatedGroups(list?.slice(offsetValue, itemLimit + offsetValue));
+    };
+
+
+    const handlePaginationChange = (event: React.MouseEvent<HTMLAnchorElement>, data: PaginationProps) => {
+        const offsetValue: number = (data.activePage as number - 1) * listItemLimit;
+
+        setListOffset(offsetValue);
+        setGroupsPage(offsetValue, listItemLimit, userGroupsList);
+    };
+
+    const handleItemsPerPageDropdownChange = (event: React.MouseEvent<HTMLAnchorElement>, data: DropdownProps) => {
+        setListItemLimit(data.value as number);
+        setGroupsPage(listOffset, data.value as number, userGroupsList);
+    };
+
+    const handleSearchQueryClear = (): void => {
+        setTriggerClearQuery(!triggerClearQuery);
+        setSearchQuery("");
+    };
+
+    const resolveTotalPages = (): number => {
+        return Math.ceil(userGroupsList?.length / listItemLimit);
+    };
+
+    const unassignUserFromGroup = (group: GroupsMemberInterface) => {
+        const operationData: PatchGroupDataInterface = {
+            Operations: [ {
+                "op": "remove",
+                "path": `members[value eq ${user.id}]`
+            } ],
+            schemas: [ "urn:ietf:params:scim:api:messages:2.0:PatchOp" ]
+        };
+
+        updateGroupDetails(group.value, operationData)
+            .then(() => {
+                dispatch(addAlert({
+                    description: t("console:manage.features.groups.notifications.updateGroup.success.description"),
+                    level: AlertLevels.SUCCESS,
+                    message: t("console:manage.features.groups.notifications.updateGroup.success.message")
+                }));
+                handleUserUpdate(user.id);
+            }).catch(() => {
+                dispatch(addAlert({
+                    description: t("console:manage.features.groups.notifications.updateGroup.error.description"),
+                    level: AlertLevels.ERROR,
+                    message: t("console:manage.features.groups.notifications.updateGroup.error.message")
+                }));
+            }).finally(() => {
+                setDeleting(false);
+                setDeletingGroup(undefined);
+                setShowDeleteConfirmationModal(false);
+            });
+    };
+
+    /**
+     * Resolves data table columns.
+     *
+     * @returns the data table columns.
+     */
+    const resolveTableColumns = (): TableColumnInterface[] => {
+        const defaultColumns: TableColumnInterface[] = [
+            {
+                allowToggleVisibility: false,
+                dataIndex: "groupName",
+                id: "groupName",
+                key: "groupName",
+                render: (group: GroupsMemberInterface): ReactNode => {
+                    const userGroup: string[] = group?.display?.split("/");
+                    const userGroupName: string = userGroup.length === 1
+                        ? userGroup[0]
+                        : userGroup[1];
+
+                    return (
+                        <Header
+                            image
+                            as="h6"
+                            className="header-with-icon"
+                            data-componentid={ `${ componentId }-item-heading` }
+                        >
+                            <UserAvatar
+                                data-componentid="users-list-item-image"
+                                name={ group.display }
+                                size="mini"
+                                image={ user.profileUrl }
+                                spaced="right"
+                                data-suppress=""
+                            />
+                            <div>
+                                { userGroupName as ReactNode }
+                            </div>
+                        </Header>
+                    );
+                },
+                title: (
+                    <div className="pl-3">
+                        { t("user:updateUser.groups.editGroups.groupList.headers.1") }
+                    </div>
+                )
+            },
+            {
+                allowToggleVisibility: false,
+                dataIndex: "domain",
+                id: "domain",
+                key: "domain",
+                render: (group: GroupsMemberInterface): ReactNode => {
+                    const userGroup: string[] = group?.display?.split("/");
+                    const domain: string = userGroup.length === 1
+                        ? userstoresConfig.primaryUserstoreName
+                        : userGroup[0];
+
+                    return (
+                        <Header
+                            image
+                            as="h6"
+                            className="header-with-icon"
+                            data-componentid={ `${ componentId }-item-heading` }
+                        >
+                            <Label size="mini">
+                                { domain }
+                            </Label>
+                        </Header>
+                    );
+                },
+                title: (
+                    <div className="pl-3">
+                        { t("user:updateUser.groups.editGroups.groupList.headers.0") }
+                    </div>
+                )
+            }
+        ];
+
+        defaultColumns.push(
+            {
+                allowToggleVisibility: false,
+                dataIndex: "action",
+                id: "actions",
+                key: "actions",
+                textAlign: "right",
+                title: ""
+            }
+        );
+
+        return defaultColumns;
+    };
+
+    /**
+     * Resolves data table actions.
+     *
+     * @returns Table actions.
+     */
+    const resolveTableActions = (): TableActionsInterface[] => {
+        const actions: TableActionsInterface[] = [
+            {
+                "data-componentid": `${ componentId }-user-list-item-delete-button`,
+                "data-testid": `${ componentId }-user-list-item-delete-button`,
+                hidden: (): boolean => isReadOnly,
+                icon: (): SemanticICONS =>  "trash alternate",
+                onClick: (e: SyntheticEvent, group: GroupsMemberInterface): void => {
+                    setDeletingGroup(group);
+                    setShowDeleteConfirmationModal(true);
+                },
+                popupText: (): string => t("common:delete"),
+                renderer: "semantic-icon"
+            }
+        ];
+
+        return actions;
+    };
+
+    /**
+     * Shows list placeholders.
+     *
+     * @returns Placeholders.
+     */
+    const showPlaceholders = (): ReactElement => {
+        // When the search returns empty.
+        if (searchQuery) {
+            return (
+                <EmptyPlaceholder
+                    action={ (
+                        <LinkButton onClick={ handleSearchQueryClear }>
+                            { t("users:usersList.search.emptyResultPlaceholder.clearButton") }
+                        </LinkButton>
+                    ) }
+                    image={ getEmptyPlaceholderIllustrations().emptySearch }
+                    imageSize="tiny"
+                    data-testid="user-mgt-empty-groups-list"
+                    title={ t("user:updateUser.groups.editGroups." +
+                        "groupList.emptyListPlaceholder.title") }
+                    subtitle={ [
+                        t("roles:list.emptyPlaceholders.search.subtitles.0",
+                            { searchQuery: searchQuery }),
+                        t("roles:list.emptyPlaceholders.search.subtitles.1")
+                    ] }
+                />
+            );
+        }
+
+        if (paginatedGroups?.length === 0) {
+            return (
+                <EmptyPlaceholder
+                    data-testid="user-mgt-empty-groups-list"
+                    title={ t("user:updateUser.groups.editGroups." +
+                        "groupList.emptyListPlaceholder.title") }
+                    subtitle={ [
+                        t("user:updateUser.groups.editGroups." +
+                                "groupList.emptyListPlaceholder.subTitle.0"),
+                        t("user:updateUser.groups.editGroups." +
+                            "groupList.emptyListPlaceholder.subTitle.1"),
+                        t("user:updateUser.groups.editGroups." +
+                            "groupList.emptyListPlaceholder.subTitle.2")
+                    ] }
+                    action={
+                        !isReadOnly && (
+                            <PrimaryButton
+                                data-testid="user-mgt-empty-groups-list-assign-group-button"
+                                onClick={ handleOpenAddNewGroupModal }
+                                loading={ isLoading }
+                                disabled={ isLoading }
+                            >
+                                <Icon name="plus"/>
+                                { t("applicationRoles:roleGroups.assignGroup") }
+                            </PrimaryButton>
+                        )
+                    }
+                    image={ getEmptyPlaceholderIllustrations().emptyList }
+                    imageSize="tiny"
+                />
+            );
+        }
+
+        return null;
+    };
+
+    return (
+        <EmphasizedSegment
+            className="list-user-roles-section"
+            data-testid="user-mgt-groups-list"
+            padded="very"
+        >
+            <Box display="flex" justifyContent="space-between" alignItems="center">
+                {
+                    (!!searchQuery || paginatedGroups?.length > 0) &&  (
+                        <div>
+                            <Heading as="h4">
+                                { t("user:updateUser.groups.editGroups.heading") }
+                            </Heading>
+                            <Heading subHeading ellipsis as="h6">
+                                { t("user:updateUser.groups.editGroups.subHeading") }
+                            </Heading>
+                        </div>
+                    )
+                }
+                { !isReadOnly && (!!searchQuery || paginatedGroups?.length > 0) && (
+                    <PrimaryButton
+                        data-testid="user-mgt-groups-list-update-button"
+                        onClick={ handleOpenAddNewGroupModal }
+                    >
+                        <Icon name="plus"/>
+                        { t("applicationRoles:roleGroups.assignGroup") }
+                    </PrimaryButton>
+                ) }
+            </Box>
+            <Divider hidden/>
+            <ListLayout
+                advancedSearch={ (
+                    <AdvancedSearchWithBasicFilters
+                        data-testid="group-mgt-groups-list-advanced-search"
+                        onFilter={ (query: string) => setSearchQuery(query?.trim()) }
+                        disableSearchFilterDropdown
+                        filterAttributeOptions={ [] }
+                        placeholder={ t("console:manage.features.groups.advancedSearch.placeholder") }
+                        defaultSearchAttribute={ "" }
+                        defaultSearchOperator={ "" }
+                        triggerClearQuery={ triggerClearQuery }
+                    />
+                ) }
+                currentListSize={ paginatedGroups?.length }
+                listItemLimit={ listItemLimit }
+                onItemsPerPageDropdownChange={ handleItemsPerPageDropdownChange }
+                data-componentid={ `${ componentId }-user-groups-list-layout` }
+                data-testid={ `${ componentId }-user-groups-list-layout` }
+                onPageChange={ handlePaginationChange }
+                showPagination={ true }
+                totalPages={ resolveTotalPages() }
+                totalListSize={ userGroupsList?.length }
+                showPaginationPageLimit={ !isReadOnly }
+                showTopActionPanel={ (!!searchQuery || userGroupsList?.length > 0) }
+            >
+                <DataTable<GroupsMemberInterface>
+                    isLoading={ isLoading }
+                    loadingStateOptions={ {
+                        count: UIConstants.DEFAULT_RESOURCE_LIST_ITEM_LIMIT,
+                        imageType: "circular"
+                    } }
+                    actions={ resolveTableActions() }
+                    columns={ resolveTableColumns() }
+                    data={ paginatedGroups }
+                    onRowClick={ () =>  null }
+                    placeholders={ showPlaceholders() }
+                    selectable={ false }
+                    showHeader={ true }
+                    data-testid={ componentId }
+                />
+            </ListLayout>
+            <ConfirmationModal
+                primaryActionLoading={ isDeleting }
+                data-testid={ `${ componentId }-confirmation-modal` }
+                data-componentid={ `${ componentId }-confirmation-modal` }
+                onClose={ (): void => setShowDeleteConfirmationModal(false) }
+                type="negative"
+                open={ showDeleteConfirmationModal }
+                primaryAction="Confirm"
+                secondaryAction="Cancel"
+                onSecondaryActionClick={ (): void => {
+                    setShowDeleteConfirmationModal(false);
+                } }
+                onPrimaryActionClick={ (): void => {
+                    setDeleting(true);
+                    unassignUserFromGroup(deletingGroup);
+                } }
+                closeOnDimmerClick={ false }
+            >
+                <ConfirmationModal.Header
+                    data-testid={ `${ componentId }-confirmation-modal-header` }
+                    data-componentid={ `${ componentId }-confirmation-modal-header` }
path: features/admin.users.v1/components/user-groups-list.tsx
user: login: pavinduLakshan
body: Since this is a new component, we maybe able to keep just componentid. WDYT?
created_at: 2025-03-20T15:44:04Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,493 @@
+/**
+ * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import Box from "@oxygen-ui/react/Box/Box";
+import { AdvancedSearchWithBasicFilters } from "@wso2is/admin.core.v1/components/advanced-search-with-basic-filters";
+import { getEmptyPlaceholderIllustrations } from "@wso2is/admin.core.v1/configs/ui";
+import { UIConstants } from "@wso2is/admin.core.v1/constants/ui-constants";
+import { userstoresConfig } from "@wso2is/admin.extensions.v1";
+import { updateGroupDetails } from "@wso2is/admin.groups.v1/api/groups";
+import { GroupsMemberInterface, PatchGroupDataInterface } from "@wso2is/admin.groups.v1/models/groups";
+import {
+    AlertLevels,
+    IdentifiableComponentInterface,
+    ProfileInfoInterface
+} from "@wso2is/core/models";
+import { addAlert } from "@wso2is/core/store";
+import {
+    ConfirmationModal,
+    DataTable,
+    EmphasizedSegment,
+    EmptyPlaceholder,
+    Heading,
+    LinkButton,
+    ListLayout,
+    PrimaryButton,
+    TableActionsInterface,
+    TableColumnInterface,
+    UserAvatar
+} from "@wso2is/react-components";
+import isEmpty from "lodash-es/isEmpty";
+import React, {
+    FunctionComponent,
+    ReactElement,
+    ReactNode,
+    SyntheticEvent,
+    useEffect,
+    useState
+} from "react";
+import { useTranslation } from "react-i18next";
+import { useDispatch } from "react-redux";
+import { Dispatch } from "redux";
+import { Divider, DropdownProps, Header, Icon, Label, PaginationProps, SemanticICONS } from "semantic-ui-react";
+import "./user-roles-list.scss";
+
+interface UserGroupsEditPropsInterface extends IdentifiableComponentInterface {
+    /**
+     * User profile
+     */
+    user: ProfileInfoInterface;
+    /**
+     * Is the component loading
+     */
+    isLoading?: boolean;
+    /**
+     * Is the component in read only mode
+     */
+    isReadOnly?: boolean;
+    /**
+     * Callback to open the add new group modal
+     */
+    handleOpenAddNewGroupModal: () => void;
+    /**
+     * Handle user update callback.
+     */
+    handleUserUpdate: (userId: string) => void;
+}
+
+export const UserGroupsListTable: FunctionComponent<UserGroupsEditPropsInterface> = (
+    props: UserGroupsEditPropsInterface
+): ReactElement => {
+
+    const {
+        user,
+        isLoading,
+        isReadOnly,
+        handleOpenAddNewGroupModal,
+        handleUserUpdate,
+        "data-componentid": componentId
+    } = props;
+
+    const { t } = useTranslation();
+
+    const dispatch: Dispatch = useDispatch();
+
+    const [ searchQuery, setSearchQuery ] = useState<string>("");
+    const [ listItemLimit, setListItemLimit ] = useState<number>(UIConstants.DEFAULT_RESOURCE_LIST_ITEM_LIMIT);
+    const [ listOffset, setListOffset ] = useState<number>(0);
+    const [ paginatedGroups, setPaginatedGroups ] = useState<GroupsMemberInterface[]>(undefined);
+    const [ triggerClearQuery, setTriggerClearQuery ] = useState<boolean>(false);
+    const [ showDeleteConfirmationModal, setShowDeleteConfirmationModal ] = useState<boolean>(false);
+    const [ deletingGroup, setDeletingGroup ] = useState<GroupsMemberInterface>(undefined);
+    const [ isDeleting, setDeleting ] = useState<boolean>(false);
+
+    const userGroupsList: GroupsMemberInterface[] = user?.groups;
+
+    /**
+     * Set initial selected roles options
+     */
+    useEffect(() => {
+        setGroupsPage(0, listItemLimit, userGroupsList, searchQuery);
+    }, [ user, searchQuery ]);
+
+    /**
+     * Util method to paginate retrieved groups  list.
+     *
+     * @param offsetValue - pagination offset value.
+     * @param itemLimit - pagination item limit.
+     * @param list - Role list.
+     */
+    const setGroupsPage = (
+        offsetValue: number,
+        itemLimit: number,
+        list: GroupsMemberInterface[],
+        searchQuery?: string
+    ) => {
+        if (!list) {
+            setPaginatedGroups([]);
+
+            return;
+        }
+
+        if (!isEmpty(searchQuery)) {
+            const filteredList: GroupsMemberInterface[] = list.filter((group: GroupsMemberInterface) => {
+                return group.display.toLowerCase().includes(searchQuery.toLowerCase());
+            });
+
+            setPaginatedGroups(filteredList?.slice(offsetValue, itemLimit + offsetValue));
+
+            return;
+        }
+
+        setPaginatedGroups(list?.slice(offsetValue, itemLimit + offsetValue));
+    };
+
+
+    const handlePaginationChange = (event: React.MouseEvent<HTMLAnchorElement>, data: PaginationProps) => {
+        const offsetValue: number = (data.activePage as number - 1) * listItemLimit;
+
+        setListOffset(offsetValue);
+        setGroupsPage(offsetValue, listItemLimit, userGroupsList);
+    };
+
+    const handleItemsPerPageDropdownChange = (event: React.MouseEvent<HTMLAnchorElement>, data: DropdownProps) => {
+        setListItemLimit(data.value as number);
+        setGroupsPage(listOffset, data.value as number, userGroupsList);
+    };
+
+    const handleSearchQueryClear = (): void => {
+        setTriggerClearQuery(!triggerClearQuery);
+        setSearchQuery("");
+    };
+
+    const resolveTotalPages = (): number => {
+        return Math.ceil(userGroupsList?.length / listItemLimit);
+    };
+
+    const unassignUserFromGroup = (group: GroupsMemberInterface) => {
+        const operationData: PatchGroupDataInterface = {
+            Operations: [ {
+                "op": "remove",
+                "path": `members[value eq ${user.id}]`
+            } ],
+            schemas: [ "urn:ietf:params:scim:api:messages:2.0:PatchOp" ]
+        };
+
+        updateGroupDetails(group.value, operationData)
+            .then(() => {
+                dispatch(addAlert({
+                    description: t("console:manage.features.groups.notifications.updateGroup.success.description"),
+                    level: AlertLevels.SUCCESS,
+                    message: t("console:manage.features.groups.notifications.updateGroup.success.message")
+                }));
+                handleUserUpdate(user.id);
+            }).catch(() => {
+                dispatch(addAlert({
+                    description: t("console:manage.features.groups.notifications.updateGroup.error.description"),
+                    level: AlertLevels.ERROR,
+                    message: t("console:manage.features.groups.notifications.updateGroup.error.message")
+                }));
+            }).finally(() => {
+                setDeleting(false);
+                setDeletingGroup(undefined);
+                setShowDeleteConfirmationModal(false);
+            });
+    };
+
+    /**
+     * Resolves data table columns.
+     *
+     * @returns the data table columns.
+     */
+    const resolveTableColumns = (): TableColumnInterface[] => {
+        const defaultColumns: TableColumnInterface[] = [
+            {
+                allowToggleVisibility: false,
+                dataIndex: "groupName",
+                id: "groupName",
+                key: "groupName",
+                render: (group: GroupsMemberInterface): ReactNode => {
+                    const userGroup: string[] = group?.display?.split("/");
+                    const userGroupName: string = userGroup.length === 1
+                        ? userGroup[0]
+                        : userGroup[1];
+
+                    return (
+                        <Header
+                            image
+                            as="h6"
+                            className="header-with-icon"
+                            data-componentid={ `${ componentId }-item-heading` }
+                        >
+                            <UserAvatar
+                                data-componentid="users-list-item-image"
+                                name={ group.display }
+                                size="mini"
+                                image={ user.profileUrl }
+                                spaced="right"
+                                data-suppress=""
+                            />
+                            <div>
+                                { userGroupName as ReactNode }
+                            </div>
+                        </Header>
+                    );
+                },
+                title: (
+                    <div className="pl-3">
+                        { t("user:updateUser.groups.editGroups.groupList.headers.1") }
+                    </div>
+                )
+            },
+            {
+                allowToggleVisibility: false,
+                dataIndex: "domain",
+                id: "domain",
+                key: "domain",
+                render: (group: GroupsMemberInterface): ReactNode => {
+                    const userGroup: string[] = group?.display?.split("/");
+                    const domain: string = userGroup.length === 1
+                        ? userstoresConfig.primaryUserstoreName
+                        : userGroup[0];
+
+                    return (
+                        <Header
+                            image
+                            as="h6"
+                            className="header-with-icon"
+                            data-componentid={ `${ componentId }-item-heading` }
+                        >
+                            <Label size="mini">
+                                { domain }
+                            </Label>
+                        </Header>
+                    );
+                },
+                title: (
+                    <div className="pl-3">
+                        { t("user:updateUser.groups.editGroups.groupList.headers.0") }
+                    </div>
+                )
+            }
+        ];
+
+        defaultColumns.push(
+            {
+                allowToggleVisibility: false,
+                dataIndex: "action",
+                id: "actions",
+                key: "actions",
+                textAlign: "right",
+                title: ""
+            }
+        );
+
+        return defaultColumns;
+    };
+
+    /**
+     * Resolves data table actions.
+     *
+     * @returns Table actions.
+     */
+    const resolveTableActions = (): TableActionsInterface[] => {
+        const actions: TableActionsInterface[] = [
+            {
+                "data-componentid": `${ componentId }-user-list-item-delete-button`,
+                "data-testid": `${ componentId }-user-list-item-delete-button`,
+                hidden: (): boolean => isReadOnly,
+                icon: (): SemanticICONS =>  "trash alternate",
+                onClick: (e: SyntheticEvent, group: GroupsMemberInterface): void => {
+                    setDeletingGroup(group);
+                    setShowDeleteConfirmationModal(true);
+                },
+                popupText: (): string => t("common:delete"),
+                renderer: "semantic-icon"
+            }
+        ];
+
+        return actions;
+    };
+
+    /**
+     * Shows list placeholders.
+     *
+     * @returns Placeholders.
+     */
+    const showPlaceholders = (): ReactElement => {
+        // When the search returns empty.
+        if (searchQuery) {
+            return (
+                <EmptyPlaceholder
+                    action={ (
+                        <LinkButton onClick={ handleSearchQueryClear }>
+                            { t("users:usersList.search.emptyResultPlaceholder.clearButton") }
+                        </LinkButton>
+                    ) }
+                    image={ getEmptyPlaceholderIllustrations().emptySearch }
+                    imageSize="tiny"
+                    data-testid="user-mgt-empty-groups-list"
+                    title={ t("user:updateUser.groups.editGroups." +
+                        "groupList.emptyListPlaceholder.title") }
+                    subtitle={ [
+                        t("roles:list.emptyPlaceholders.search.subtitles.0",
+                            { searchQuery: searchQuery }),
+                        t("roles:list.emptyPlaceholders.search.subtitles.1")
+                    ] }
+                />
+            );
+        }
+
+        if (paginatedGroups?.length === 0) {
+            return (
+                <EmptyPlaceholder
+                    data-testid="user-mgt-empty-groups-list"
+                    title={ t("user:updateUser.groups.editGroups." +
+                        "groupList.emptyListPlaceholder.title") }
+                    subtitle={ [
+                        t("user:updateUser.groups.editGroups." +
+                                "groupList.emptyListPlaceholder.subTitle.0"),
+                        t("user:updateUser.groups.editGroups." +
+                            "groupList.emptyListPlaceholder.subTitle.1"),
+                        t("user:updateUser.groups.editGroups." +
+                            "groupList.emptyListPlaceholder.subTitle.2")
+                    ] }
+                    action={
+                        !isReadOnly && (
+                            <PrimaryButton
+                                data-testid="user-mgt-empty-groups-list-assign-group-button"
+                                onClick={ handleOpenAddNewGroupModal }
+                                loading={ isLoading }
+                                disabled={ isLoading }
+                            >
+                                <Icon name="plus"/>
+                                { t("applicationRoles:roleGroups.assignGroup") }
+                            </PrimaryButton>
+                        )
+                    }
+                    image={ getEmptyPlaceholderIllustrations().emptyList }
+                    imageSize="tiny"
+                />
+            );
+        }
+
+        return null;
+    };
+
+    return (
+        <EmphasizedSegment
+            className="list-user-roles-section"
+            data-testid="user-mgt-groups-list"
+            padded="very"
+        >
+            <Box display="flex" justifyContent="space-between" alignItems="center">
+                {
+                    (!!searchQuery || paginatedGroups?.length > 0) &&  (
+                        <div>
+                            <Heading as="h4">
+                                { t("user:updateUser.groups.editGroups.heading") }
+                            </Heading>
+                            <Heading subHeading ellipsis as="h6">
+                                { t("user:updateUser.groups.editGroups.subHeading") }
+                            </Heading>
+                        </div>
+                    )
+                }
+                { !isReadOnly && (!!searchQuery || paginatedGroups?.length > 0) && (
+                    <PrimaryButton
+                        data-testid="user-mgt-groups-list-update-button"
+                        onClick={ handleOpenAddNewGroupModal }
+                    >
+                        <Icon name="plus"/>
+                        { t("applicationRoles:roleGroups.assignGroup") }
+                    </PrimaryButton>
+                ) }
+            </Box>
+            <Divider hidden/>
+            <ListLayout
+                advancedSearch={ (
+                    <AdvancedSearchWithBasicFilters
+                        data-testid="group-mgt-groups-list-advanced-search"
+                        onFilter={ (query: string) => setSearchQuery(query?.trim()) }
+                        disableSearchFilterDropdown
+                        filterAttributeOptions={ [] }
+                        placeholder={ t("console:manage.features.groups.advancedSearch.placeholder") }
+                        defaultSearchAttribute={ "" }
+                        defaultSearchOperator={ "" }
+                        triggerClearQuery={ triggerClearQuery }
+                    />
+                ) }
+                currentListSize={ paginatedGroups?.length }
+                listItemLimit={ listItemLimit }
+                onItemsPerPageDropdownChange={ handleItemsPerPageDropdownChange }
+                data-componentid={ `${ componentId }-user-groups-list-layout` }
+                data-testid={ `${ componentId }-user-groups-list-layout` }
+                onPageChange={ handlePaginationChange }
+                showPagination={ true }
+                totalPages={ resolveTotalPages() }
+                totalListSize={ userGroupsList?.length }
+                showPaginationPageLimit={ !isReadOnly }
+                showTopActionPanel={ (!!searchQuery || userGroupsList?.length > 0) }
+            >
+                <DataTable<GroupsMemberInterface>
+                    isLoading={ isLoading }
+                    loadingStateOptions={ {
+                        count: UIConstants.DEFAULT_RESOURCE_LIST_ITEM_LIMIT,
+                        imageType: "circular"
+                    } }
+                    actions={ resolveTableActions() }
+                    columns={ resolveTableColumns() }
+                    data={ paginatedGroups }
+                    onRowClick={ () =>  null }
+                    placeholders={ showPlaceholders() }
+                    selectable={ false }
+                    showHeader={ true }
+                    data-testid={ componentId }
+                />
+            </ListLayout>
+            <ConfirmationModal
+                primaryActionLoading={ isDeleting }
+                data-testid={ `${ componentId }-confirmation-modal` }
+                data-componentid={ `${ componentId }-confirmation-modal` }
+                onClose={ (): void => setShowDeleteConfirmationModal(false) }
+                type="negative"
+                open={ showDeleteConfirmationModal }
+                primaryAction="Confirm"
+                secondaryAction="Cancel"
+                onSecondaryActionClick={ (): void => {
+                    setShowDeleteConfirmationModal(false);
+                } }
+                onPrimaryActionClick={ (): void => {
+                    setDeleting(true);
+                    unassignUserFromGroup(deletingGroup);
+                } }
+                closeOnDimmerClick={ false }
+            >
+                <ConfirmationModal.Header
+                    data-testid={ `${ componentId }-confirmation-modal-header` }
+                    data-componentid={ `${ componentId }-confirmation-modal-header` }
+                >
+                    { t("users:confirmations.unassignGroup.header") }
+                </ConfirmationModal.Header>
+                <ConfirmationModal.Content
+                    data-testid={ `${ componentId }-confirmation-modal-content` }
+                    data-componentid={ `${ componentId }-confirmation-modal-content` }
+                >
+                    { t("users:confirmations.unassignGroup.content") }
+                </ConfirmationModal.Content>
+            </ConfirmationModal>
+        </EmphasizedSegment>
+    );
+};
+
+/**
+ * Default props for user groups list tab component.
+ */
+UserGroupsListTable.defaultProps = {
path: features/admin.users.v1/components/user-groups-list.tsx
user: login: pavinduLakshan
body: https://github.com/wso2/identity-apps/blob/master/docs/write-code/CODE_QUALITY.md#refrain-from-using-defaultprops
created_at: 2025-03-20T15:44:50Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,6 @@
+---
+"@wso2is/admin.users.v1": patch
+"@wso2is/i18n": patch
+---
path: .changeset/curvy-insects-design.md
user: login: DonOmalVindula
body: Fixed with cb0ee2cf165319ca096aa44d358799060f08bbf9
created_at: 2025-03-21T11:17:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,493 @@
+/**
+ * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import Box from "@oxygen-ui/react/Box/Box";
path: features/admin.users.v1/components/user-groups-list.tsx
user: login: DonOmalVindula
body: Fixed with cb0ee2cf165319ca096aa44d358799060f08bbf9
created_at: 2025-03-21T11:17:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,493 @@
+/**
+ * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import Box from "@oxygen-ui/react/Box/Box";
+import { AdvancedSearchWithBasicFilters } from "@wso2is/admin.core.v1/components/advanced-search-with-basic-filters";
+import { getEmptyPlaceholderIllustrations } from "@wso2is/admin.core.v1/configs/ui";
+import { UIConstants } from "@wso2is/admin.core.v1/constants/ui-constants";
+import { userstoresConfig } from "@wso2is/admin.extensions.v1";
+import { updateGroupDetails } from "@wso2is/admin.groups.v1/api/groups";
+import { GroupsMemberInterface, PatchGroupDataInterface } from "@wso2is/admin.groups.v1/models/groups";
+import {
+    AlertLevels,
+    IdentifiableComponentInterface,
+    ProfileInfoInterface
+} from "@wso2is/core/models";
+import { addAlert } from "@wso2is/core/store";
+import {
+    ConfirmationModal,
+    DataTable,
+    EmphasizedSegment,
+    EmptyPlaceholder,
+    Heading,
+    LinkButton,
+    ListLayout,
+    PrimaryButton,
+    TableActionsInterface,
+    TableColumnInterface,
+    UserAvatar
+} from "@wso2is/react-components";
+import isEmpty from "lodash-es/isEmpty";
+import React, {
+    FunctionComponent,
+    ReactElement,
+    ReactNode,
+    SyntheticEvent,
+    useEffect,
+    useState
+} from "react";
+import { useTranslation } from "react-i18next";
+import { useDispatch } from "react-redux";
+import { Dispatch } from "redux";
+import { Divider, DropdownProps, Header, Icon, Label, PaginationProps, SemanticICONS } from "semantic-ui-react";
+import "./user-roles-list.scss";
+
+interface UserGroupsEditPropsInterface extends IdentifiableComponentInterface {
+    /**
+     * User profile
+     */
+    user: ProfileInfoInterface;
+    /**
+     * Is the component loading
+     */
+    isLoading?: boolean;
+    /**
+     * Is the component in read only mode
+     */
+    isReadOnly?: boolean;
+    /**
+     * Callback to open the add new group modal
+     */
+    handleOpenAddNewGroupModal: () => void;
+    /**
+     * Handle user update callback.
+     */
+    handleUserUpdate: (userId: string) => void;
+}
+
+export const UserGroupsListTable: FunctionComponent<UserGroupsEditPropsInterface> = (
path: features/admin.users.v1/components/user-groups-list.tsx
user: login: DonOmalVindula
body: Fixed with cb0ee2cf165319ca096aa44d358799060f08bbf9
created_at: 2025-03-21T11:17:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,493 @@
+/**
+ * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import Box from "@oxygen-ui/react/Box/Box";
+import { AdvancedSearchWithBasicFilters } from "@wso2is/admin.core.v1/components/advanced-search-with-basic-filters";
+import { getEmptyPlaceholderIllustrations } from "@wso2is/admin.core.v1/configs/ui";
+import { UIConstants } from "@wso2is/admin.core.v1/constants/ui-constants";
+import { userstoresConfig } from "@wso2is/admin.extensions.v1";
+import { updateGroupDetails } from "@wso2is/admin.groups.v1/api/groups";
+import { GroupsMemberInterface, PatchGroupDataInterface } from "@wso2is/admin.groups.v1/models/groups";
+import {
+    AlertLevels,
+    IdentifiableComponentInterface,
+    ProfileInfoInterface
+} from "@wso2is/core/models";
+import { addAlert } from "@wso2is/core/store";
+import {
+    ConfirmationModal,
+    DataTable,
+    EmphasizedSegment,
+    EmptyPlaceholder,
+    Heading,
+    LinkButton,
+    ListLayout,
+    PrimaryButton,
+    TableActionsInterface,
+    TableColumnInterface,
+    UserAvatar
+} from "@wso2is/react-components";
+import isEmpty from "lodash-es/isEmpty";
+import React, {
+    FunctionComponent,
+    ReactElement,
+    ReactNode,
+    SyntheticEvent,
+    useEffect,
+    useState
+} from "react";
+import { useTranslation } from "react-i18next";
+import { useDispatch } from "react-redux";
+import { Dispatch } from "redux";
+import { Divider, DropdownProps, Header, Icon, Label, PaginationProps, SemanticICONS } from "semantic-ui-react";
+import "./user-roles-list.scss";
+
+interface UserGroupsEditPropsInterface extends IdentifiableComponentInterface {
+    /**
+     * User profile
+     */
+    user: ProfileInfoInterface;
+    /**
+     * Is the component loading
+     */
+    isLoading?: boolean;
+    /**
+     * Is the component in read only mode
+     */
+    isReadOnly?: boolean;
+    /**
+     * Callback to open the add new group modal
+     */
+    handleOpenAddNewGroupModal: () => void;
+    /**
+     * Handle user update callback.
+     */
+    handleUserUpdate: (userId: string) => void;
+}
+
+export const UserGroupsListTable: FunctionComponent<UserGroupsEditPropsInterface> = (
+    props: UserGroupsEditPropsInterface
+): ReactElement => {
+
+    const {
+        user,
+        isLoading,
+        isReadOnly,
+        handleOpenAddNewGroupModal,
+        handleUserUpdate,
+        "data-componentid": componentId
+    } = props;
+
+    const { t } = useTranslation();
+
+    const dispatch: Dispatch = useDispatch();
+
+    const [ searchQuery, setSearchQuery ] = useState<string>("");
+    const [ listItemLimit, setListItemLimit ] = useState<number>(UIConstants.DEFAULT_RESOURCE_LIST_ITEM_LIMIT);
+    const [ listOffset, setListOffset ] = useState<number>(0);
+    const [ paginatedGroups, setPaginatedGroups ] = useState<GroupsMemberInterface[]>(undefined);
+    const [ triggerClearQuery, setTriggerClearQuery ] = useState<boolean>(false);
+    const [ showDeleteConfirmationModal, setShowDeleteConfirmationModal ] = useState<boolean>(false);
+    const [ deletingGroup, setDeletingGroup ] = useState<GroupsMemberInterface>(undefined);
+    const [ isDeleting, setDeleting ] = useState<boolean>(false);
+
+    const userGroupsList: GroupsMemberInterface[] = user?.groups;
+
+    /**
+     * Set initial selected roles options
+     */
+    useEffect(() => {
+        setGroupsPage(0, listItemLimit, userGroupsList, searchQuery);
path: features/admin.users.v1/components/user-groups-list.tsx
user: login: DonOmalVindula
body: Fixed with cb0ee2cf165319ca096aa44d358799060f08bbf9
created_at: 2025-03-21T11:17:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,493 @@
+/**
+ * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import Box from "@oxygen-ui/react/Box/Box";
+import { AdvancedSearchWithBasicFilters } from "@wso2is/admin.core.v1/components/advanced-search-with-basic-filters";
+import { getEmptyPlaceholderIllustrations } from "@wso2is/admin.core.v1/configs/ui";
+import { UIConstants } from "@wso2is/admin.core.v1/constants/ui-constants";
+import { userstoresConfig } from "@wso2is/admin.extensions.v1";
+import { updateGroupDetails } from "@wso2is/admin.groups.v1/api/groups";
+import { GroupsMemberInterface, PatchGroupDataInterface } from "@wso2is/admin.groups.v1/models/groups";
+import {
+    AlertLevels,
+    IdentifiableComponentInterface,
+    ProfileInfoInterface
+} from "@wso2is/core/models";
+import { addAlert } from "@wso2is/core/store";
+import {
+    ConfirmationModal,
+    DataTable,
+    EmphasizedSegment,
+    EmptyPlaceholder,
+    Heading,
+    LinkButton,
+    ListLayout,
+    PrimaryButton,
+    TableActionsInterface,
+    TableColumnInterface,
+    UserAvatar
+} from "@wso2is/react-components";
+import isEmpty from "lodash-es/isEmpty";
+import React, {
+    FunctionComponent,
+    ReactElement,
+    ReactNode,
+    SyntheticEvent,
+    useEffect,
+    useState
+} from "react";
+import { useTranslation } from "react-i18next";
+import { useDispatch } from "react-redux";
+import { Dispatch } from "redux";
+import { Divider, DropdownProps, Header, Icon, Label, PaginationProps, SemanticICONS } from "semantic-ui-react";
+import "./user-roles-list.scss";
+
+interface UserGroupsEditPropsInterface extends IdentifiableComponentInterface {
+    /**
+     * User profile
+     */
+    user: ProfileInfoInterface;
+    /**
+     * Is the component loading
+     */
+    isLoading?: boolean;
+    /**
+     * Is the component in read only mode
+     */
+    isReadOnly?: boolean;
+    /**
+     * Callback to open the add new group modal
+     */
+    handleOpenAddNewGroupModal: () => void;
+    /**
+     * Handle user update callback.
+     */
+    handleUserUpdate: (userId: string) => void;
+}
+
+export const UserGroupsListTable: FunctionComponent<UserGroupsEditPropsInterface> = (
+    props: UserGroupsEditPropsInterface
+): ReactElement => {
+
+    const {
+        user,
+        isLoading,
+        isReadOnly,
+        handleOpenAddNewGroupModal,
+        handleUserUpdate,
+        "data-componentid": componentId
+    } = props;
+
+    const { t } = useTranslation();
+
+    const dispatch: Dispatch = useDispatch();
+
+    const [ searchQuery, setSearchQuery ] = useState<string>("");
+    const [ listItemLimit, setListItemLimit ] = useState<number>(UIConstants.DEFAULT_RESOURCE_LIST_ITEM_LIMIT);
+    const [ listOffset, setListOffset ] = useState<number>(0);
+    const [ paginatedGroups, setPaginatedGroups ] = useState<GroupsMemberInterface[]>(undefined);
+    const [ triggerClearQuery, setTriggerClearQuery ] = useState<boolean>(false);
+    const [ showDeleteConfirmationModal, setShowDeleteConfirmationModal ] = useState<boolean>(false);
+    const [ deletingGroup, setDeletingGroup ] = useState<GroupsMemberInterface>(undefined);
+    const [ isDeleting, setDeleting ] = useState<boolean>(false);
+
+    const userGroupsList: GroupsMemberInterface[] = user?.groups;
+
+    /**
+     * Set initial selected roles options
+     */
+    useEffect(() => {
+        setGroupsPage(0, listItemLimit, userGroupsList, searchQuery);
+    }, [ user, searchQuery ]);
+
+    /**
+     * Util method to paginate retrieved groups  list.
+     *
+     * @param offsetValue - pagination offset value.
+     * @param itemLimit - pagination item limit.
+     * @param list - Role list.
+     */
+    const setGroupsPage = (
+        offsetValue: number,
+        itemLimit: number,
+        list: GroupsMemberInterface[],
+        searchQuery?: string
+    ) => {
+        if (!list) {
+            setPaginatedGroups([]);
+
+            return;
+        }
+
+        if (!isEmpty(searchQuery)) {
+            const filteredList: GroupsMemberInterface[] = list.filter((group: GroupsMemberInterface) => {
+                return group.display.toLowerCase().includes(searchQuery.toLowerCase());
+            });
+
+            setPaginatedGroups(filteredList?.slice(offsetValue, itemLimit + offsetValue));
+
+            return;
+        }
+
+        setPaginatedGroups(list?.slice(offsetValue, itemLimit + offsetValue));
+    };
+
+
+    const handlePaginationChange = (event: React.MouseEvent<HTMLAnchorElement>, data: PaginationProps) => {
+        const offsetValue: number = (data.activePage as number - 1) * listItemLimit;
+
+        setListOffset(offsetValue);
+        setGroupsPage(offsetValue, listItemLimit, userGroupsList);
+    };
+
+    const handleItemsPerPageDropdownChange = (event: React.MouseEvent<HTMLAnchorElement>, data: DropdownProps) => {
+        setListItemLimit(data.value as number);
+        setGroupsPage(listOffset, data.value as number, userGroupsList);
+    };
+
+    const handleSearchQueryClear = (): void => {
+        setTriggerClearQuery(!triggerClearQuery);
+        setSearchQuery("");
+    };
+
+    const resolveTotalPages = (): number => {
+        return Math.ceil(userGroupsList?.length / listItemLimit);
+    };
+
+    const unassignUserFromGroup = (group: GroupsMemberInterface) => {
path: features/admin.users.v1/components/user-groups-list.tsx
user: login: DonOmalVindula
body: Fixed with cb0ee2cf165319ca096aa44d358799060f08bbf9
created_at: 2025-03-21T11:17:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,493 @@
+/**
+ * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import Box from "@oxygen-ui/react/Box/Box";
+import { AdvancedSearchWithBasicFilters } from "@wso2is/admin.core.v1/components/advanced-search-with-basic-filters";
+import { getEmptyPlaceholderIllustrations } from "@wso2is/admin.core.v1/configs/ui";
+import { UIConstants } from "@wso2is/admin.core.v1/constants/ui-constants";
+import { userstoresConfig } from "@wso2is/admin.extensions.v1";
+import { updateGroupDetails } from "@wso2is/admin.groups.v1/api/groups";
+import { GroupsMemberInterface, PatchGroupDataInterface } from "@wso2is/admin.groups.v1/models/groups";
+import {
+    AlertLevels,
+    IdentifiableComponentInterface,
+    ProfileInfoInterface
+} from "@wso2is/core/models";
+import { addAlert } from "@wso2is/core/store";
+import {
+    ConfirmationModal,
+    DataTable,
+    EmphasizedSegment,
+    EmptyPlaceholder,
+    Heading,
+    LinkButton,
+    ListLayout,
+    PrimaryButton,
+    TableActionsInterface,
+    TableColumnInterface,
+    UserAvatar
+} from "@wso2is/react-components";
+import isEmpty from "lodash-es/isEmpty";
+import React, {
+    FunctionComponent,
+    ReactElement,
+    ReactNode,
+    SyntheticEvent,
+    useEffect,
+    useState
+} from "react";
+import { useTranslation } from "react-i18next";
+import { useDispatch } from "react-redux";
+import { Dispatch } from "redux";
+import { Divider, DropdownProps, Header, Icon, Label, PaginationProps, SemanticICONS } from "semantic-ui-react";
+import "./user-roles-list.scss";
+
+interface UserGroupsEditPropsInterface extends IdentifiableComponentInterface {
+    /**
+     * User profile
+     */
+    user: ProfileInfoInterface;
+    /**
+     * Is the component loading
+     */
+    isLoading?: boolean;
+    /**
+     * Is the component in read only mode
+     */
+    isReadOnly?: boolean;
+    /**
+     * Callback to open the add new group modal
+     */
+    handleOpenAddNewGroupModal: () => void;
+    /**
+     * Handle user update callback.
+     */
+    handleUserUpdate: (userId: string) => void;
+}
+
+export const UserGroupsListTable: FunctionComponent<UserGroupsEditPropsInterface> = (
+    props: UserGroupsEditPropsInterface
+): ReactElement => {
+
+    const {
+        user,
+        isLoading,
+        isReadOnly,
+        handleOpenAddNewGroupModal,
+        handleUserUpdate,
+        "data-componentid": componentId
+    } = props;
+
+    const { t } = useTranslation();
+
+    const dispatch: Dispatch = useDispatch();
+
+    const [ searchQuery, setSearchQuery ] = useState<string>("");
+    const [ listItemLimit, setListItemLimit ] = useState<number>(UIConstants.DEFAULT_RESOURCE_LIST_ITEM_LIMIT);
+    const [ listOffset, setListOffset ] = useState<number>(0);
+    const [ paginatedGroups, setPaginatedGroups ] = useState<GroupsMemberInterface[]>(undefined);
+    const [ triggerClearQuery, setTriggerClearQuery ] = useState<boolean>(false);
+    const [ showDeleteConfirmationModal, setShowDeleteConfirmationModal ] = useState<boolean>(false);
+    const [ deletingGroup, setDeletingGroup ] = useState<GroupsMemberInterface>(undefined);
+    const [ isDeleting, setDeleting ] = useState<boolean>(false);
+
+    const userGroupsList: GroupsMemberInterface[] = user?.groups;
+
+    /**
+     * Set initial selected roles options
+     */
+    useEffect(() => {
+        setGroupsPage(0, listItemLimit, userGroupsList, searchQuery);
+    }, [ user, searchQuery ]);
+
+    /**
+     * Util method to paginate retrieved groups  list.
+     *
+     * @param offsetValue - pagination offset value.
+     * @param itemLimit - pagination item limit.
+     * @param list - Role list.
+     */
+    const setGroupsPage = (
+        offsetValue: number,
+        itemLimit: number,
+        list: GroupsMemberInterface[],
+        searchQuery?: string
+    ) => {
+        if (!list) {
+            setPaginatedGroups([]);
+
+            return;
+        }
+
+        if (!isEmpty(searchQuery)) {
+            const filteredList: GroupsMemberInterface[] = list.filter((group: GroupsMemberInterface) => {
+                return group.display.toLowerCase().includes(searchQuery.toLowerCase());
+            });
+
+            setPaginatedGroups(filteredList?.slice(offsetValue, itemLimit + offsetValue));
+
+            return;
+        }
+
+        setPaginatedGroups(list?.slice(offsetValue, itemLimit + offsetValue));
+    };
+
+
+    const handlePaginationChange = (event: React.MouseEvent<HTMLAnchorElement>, data: PaginationProps) => {
+        const offsetValue: number = (data.activePage as number - 1) * listItemLimit;
+
+        setListOffset(offsetValue);
+        setGroupsPage(offsetValue, listItemLimit, userGroupsList);
+    };
+
+    const handleItemsPerPageDropdownChange = (event: React.MouseEvent<HTMLAnchorElement>, data: DropdownProps) => {
+        setListItemLimit(data.value as number);
+        setGroupsPage(listOffset, data.value as number, userGroupsList);
+    };
+
+    const handleSearchQueryClear = (): void => {
+        setTriggerClearQuery(!triggerClearQuery);
+        setSearchQuery("");
+    };
+
+    const resolveTotalPages = (): number => {
+        return Math.ceil(userGroupsList?.length / listItemLimit);
+    };
+
+    const unassignUserFromGroup = (group: GroupsMemberInterface) => {
+        const operationData: PatchGroupDataInterface = {
+            Operations: [ {
+                "op": "remove",
+                "path": `members[value eq ${user.id}]`
+            } ],
+            schemas: [ "urn:ietf:params:scim:api:messages:2.0:PatchOp" ]
+        };
+
+        updateGroupDetails(group.value, operationData)
+            .then(() => {
+                dispatch(addAlert({
+                    description: t("console:manage.features.groups.notifications.updateGroup.success.description"),
+                    level: AlertLevels.SUCCESS,
+                    message: t("console:manage.features.groups.notifications.updateGroup.success.message")
+                }));
+                handleUserUpdate(user.id);
+            }).catch(() => {
+                dispatch(addAlert({
+                    description: t("console:manage.features.groups.notifications.updateGroup.error.description"),
+                    level: AlertLevels.ERROR,
+                    message: t("console:manage.features.groups.notifications.updateGroup.error.message")
+                }));
+            }).finally(() => {
+                setDeleting(false);
+                setDeletingGroup(undefined);
+                setShowDeleteConfirmationModal(false);
+            });
+    };
+
+    /**
+     * Resolves data table columns.
+     *
+     * @returns the data table columns.
+     */
+    const resolveTableColumns = (): TableColumnInterface[] => {
+        const defaultColumns: TableColumnInterface[] = [
+            {
+                allowToggleVisibility: false,
+                dataIndex: "groupName",
+                id: "groupName",
+                key: "groupName",
+                render: (group: GroupsMemberInterface): ReactNode => {
+                    const userGroup: string[] = group?.display?.split("/");
+                    const userGroupName: string = userGroup.length === 1
+                        ? userGroup[0]
+                        : userGroup[1];
+
+                    return (
+                        <Header
+                            image
+                            as="h6"
+                            className="header-with-icon"
+                            data-componentid={ `${ componentId }-item-heading` }
+                        >
+                            <UserAvatar
+                                data-componentid="users-list-item-image"
+                                name={ group.display }
+                                size="mini"
+                                image={ user.profileUrl }
+                                spaced="right"
+                                data-suppress=""
+                            />
+                            <div>
+                                { userGroupName as ReactNode }
+                            </div>
+                        </Header>
+                    );
+                },
+                title: (
+                    <div className="pl-3">
+                        { t("user:updateUser.groups.editGroups.groupList.headers.1") }
+                    </div>
+                )
+            },
+            {
+                allowToggleVisibility: false,
+                dataIndex: "domain",
+                id: "domain",
+                key: "domain",
+                render: (group: GroupsMemberInterface): ReactNode => {
+                    const userGroup: string[] = group?.display?.split("/");
path: features/admin.users.v1/components/user-groups-list.tsx
user: login: DonOmalVindula
body: Fixed with cb0ee2cf165319ca096aa44d358799060f08bbf9
created_at: 2025-03-21T11:17:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,493 @@
+/**
+ * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import Box from "@oxygen-ui/react/Box/Box";
+import { AdvancedSearchWithBasicFilters } from "@wso2is/admin.core.v1/components/advanced-search-with-basic-filters";
+import { getEmptyPlaceholderIllustrations } from "@wso2is/admin.core.v1/configs/ui";
+import { UIConstants } from "@wso2is/admin.core.v1/constants/ui-constants";
+import { userstoresConfig } from "@wso2is/admin.extensions.v1";
+import { updateGroupDetails } from "@wso2is/admin.groups.v1/api/groups";
+import { GroupsMemberInterface, PatchGroupDataInterface } from "@wso2is/admin.groups.v1/models/groups";
+import {
+    AlertLevels,
+    IdentifiableComponentInterface,
+    ProfileInfoInterface
+} from "@wso2is/core/models";
+import { addAlert } from "@wso2is/core/store";
+import {
+    ConfirmationModal,
+    DataTable,
+    EmphasizedSegment,
+    EmptyPlaceholder,
+    Heading,
+    LinkButton,
+    ListLayout,
+    PrimaryButton,
+    TableActionsInterface,
+    TableColumnInterface,
+    UserAvatar
+} from "@wso2is/react-components";
+import isEmpty from "lodash-es/isEmpty";
+import React, {
+    FunctionComponent,
+    ReactElement,
+    ReactNode,
+    SyntheticEvent,
+    useEffect,
+    useState
+} from "react";
+import { useTranslation } from "react-i18next";
+import { useDispatch } from "react-redux";
+import { Dispatch } from "redux";
+import { Divider, DropdownProps, Header, Icon, Label, PaginationProps, SemanticICONS } from "semantic-ui-react";
+import "./user-roles-list.scss";
+
+interface UserGroupsEditPropsInterface extends IdentifiableComponentInterface {
+    /**
+     * User profile
+     */
+    user: ProfileInfoInterface;
+    /**
+     * Is the component loading
+     */
+    isLoading?: boolean;
+    /**
+     * Is the component in read only mode
+     */
+    isReadOnly?: boolean;
+    /**
+     * Callback to open the add new group modal
+     */
+    handleOpenAddNewGroupModal: () => void;
+    /**
+     * Handle user update callback.
+     */
+    handleUserUpdate: (userId: string) => void;
+}
+
+export const UserGroupsListTable: FunctionComponent<UserGroupsEditPropsInterface> = (
+    props: UserGroupsEditPropsInterface
+): ReactElement => {
+
+    const {
+        user,
+        isLoading,
+        isReadOnly,
+        handleOpenAddNewGroupModal,
+        handleUserUpdate,
+        "data-componentid": componentId
+    } = props;
+
+    const { t } = useTranslation();
+
+    const dispatch: Dispatch = useDispatch();
+
+    const [ searchQuery, setSearchQuery ] = useState<string>("");
+    const [ listItemLimit, setListItemLimit ] = useState<number>(UIConstants.DEFAULT_RESOURCE_LIST_ITEM_LIMIT);
+    const [ listOffset, setListOffset ] = useState<number>(0);
+    const [ paginatedGroups, setPaginatedGroups ] = useState<GroupsMemberInterface[]>(undefined);
+    const [ triggerClearQuery, setTriggerClearQuery ] = useState<boolean>(false);
+    const [ showDeleteConfirmationModal, setShowDeleteConfirmationModal ] = useState<boolean>(false);
+    const [ deletingGroup, setDeletingGroup ] = useState<GroupsMemberInterface>(undefined);
+    const [ isDeleting, setDeleting ] = useState<boolean>(false);
+
+    const userGroupsList: GroupsMemberInterface[] = user?.groups;
+
+    /**
+     * Set initial selected roles options
+     */
+    useEffect(() => {
+        setGroupsPage(0, listItemLimit, userGroupsList, searchQuery);
+    }, [ user, searchQuery ]);
+
+    /**
+     * Util method to paginate retrieved groups  list.
+     *
+     * @param offsetValue - pagination offset value.
+     * @param itemLimit - pagination item limit.
+     * @param list - Role list.
+     */
+    const setGroupsPage = (
+        offsetValue: number,
+        itemLimit: number,
+        list: GroupsMemberInterface[],
+        searchQuery?: string
+    ) => {
+        if (!list) {
+            setPaginatedGroups([]);
+
+            return;
+        }
+
+        if (!isEmpty(searchQuery)) {
+            const filteredList: GroupsMemberInterface[] = list.filter((group: GroupsMemberInterface) => {
+                return group.display.toLowerCase().includes(searchQuery.toLowerCase());
+            });
+
+            setPaginatedGroups(filteredList?.slice(offsetValue, itemLimit + offsetValue));
+
+            return;
+        }
+
+        setPaginatedGroups(list?.slice(offsetValue, itemLimit + offsetValue));
+    };
+
+
+    const handlePaginationChange = (event: React.MouseEvent<HTMLAnchorElement>, data: PaginationProps) => {
+        const offsetValue: number = (data.activePage as number - 1) * listItemLimit;
+
+        setListOffset(offsetValue);
+        setGroupsPage(offsetValue, listItemLimit, userGroupsList);
+    };
+
+    const handleItemsPerPageDropdownChange = (event: React.MouseEvent<HTMLAnchorElement>, data: DropdownProps) => {
+        setListItemLimit(data.value as number);
+        setGroupsPage(listOffset, data.value as number, userGroupsList);
+    };
+
+    const handleSearchQueryClear = (): void => {
+        setTriggerClearQuery(!triggerClearQuery);
+        setSearchQuery("");
+    };
+
+    const resolveTotalPages = (): number => {
+        return Math.ceil(userGroupsList?.length / listItemLimit);
+    };
+
+    const unassignUserFromGroup = (group: GroupsMemberInterface) => {
+        const operationData: PatchGroupDataInterface = {
+            Operations: [ {
+                "op": "remove",
+                "path": `members[value eq ${user.id}]`
+            } ],
+            schemas: [ "urn:ietf:params:scim:api:messages:2.0:PatchOp" ]
+        };
+
+        updateGroupDetails(group.value, operationData)
+            .then(() => {
+                dispatch(addAlert({
+                    description: t("console:manage.features.groups.notifications.updateGroup.success.description"),
+                    level: AlertLevels.SUCCESS,
+                    message: t("console:manage.features.groups.notifications.updateGroup.success.message")
+                }));
+                handleUserUpdate(user.id);
+            }).catch(() => {
+                dispatch(addAlert({
+                    description: t("console:manage.features.groups.notifications.updateGroup.error.description"),
+                    level: AlertLevels.ERROR,
+                    message: t("console:manage.features.groups.notifications.updateGroup.error.message")
+                }));
+            }).finally(() => {
+                setDeleting(false);
+                setDeletingGroup(undefined);
+                setShowDeleteConfirmationModal(false);
+            });
+    };
+
+    /**
+     * Resolves data table columns.
+     *
+     * @returns the data table columns.
+     */
+    const resolveTableColumns = (): TableColumnInterface[] => {
+        const defaultColumns: TableColumnInterface[] = [
+            {
+                allowToggleVisibility: false,
+                dataIndex: "groupName",
+                id: "groupName",
+                key: "groupName",
+                render: (group: GroupsMemberInterface): ReactNode => {
+                    const userGroup: string[] = group?.display?.split("/");
+                    const userGroupName: string = userGroup.length === 1
+                        ? userGroup[0]
+                        : userGroup[1];
+
+                    return (
+                        <Header
+                            image
+                            as="h6"
+                            className="header-with-icon"
+                            data-componentid={ `${ componentId }-item-heading` }
+                        >
+                            <UserAvatar
+                                data-componentid="users-list-item-image"
+                                name={ group.display }
+                                size="mini"
+                                image={ user.profileUrl }
+                                spaced="right"
+                                data-suppress=""
+                            />
+                            <div>
+                                { userGroupName as ReactNode }
+                            </div>
+                        </Header>
+                    );
+                },
+                title: (
+                    <div className="pl-3">
+                        { t("user:updateUser.groups.editGroups.groupList.headers.1") }
+                    </div>
+                )
+            },
+            {
+                allowToggleVisibility: false,
+                dataIndex: "domain",
+                id: "domain",
+                key: "domain",
+                render: (group: GroupsMemberInterface): ReactNode => {
+                    const userGroup: string[] = group?.display?.split("/");
+                    const domain: string = userGroup.length === 1
+                        ? userstoresConfig.primaryUserstoreName
+                        : userGroup[0];
+
+                    return (
+                        <Header
+                            image
+                            as="h6"
+                            className="header-with-icon"
+                            data-componentid={ `${ componentId }-item-heading` }
+                        >
+                            <Label size="mini">
+                                { domain }
+                            </Label>
+                        </Header>
+                    );
+                },
+                title: (
+                    <div className="pl-3">
+                        { t("user:updateUser.groups.editGroups.groupList.headers.0") }
+                    </div>
+                )
+            }
+        ];
+
+        defaultColumns.push(
+            {
+                allowToggleVisibility: false,
+                dataIndex: "action",
+                id: "actions",
+                key: "actions",
+                textAlign: "right",
+                title: ""
+            }
+        );
+
+        return defaultColumns;
+    };
+
+    /**
+     * Resolves data table actions.
+     *
+     * @returns Table actions.
+     */
+    const resolveTableActions = (): TableActionsInterface[] => {
+        const actions: TableActionsInterface[] = [
+            {
+                "data-componentid": `${ componentId }-user-list-item-delete-button`,
+                "data-testid": `${ componentId }-user-list-item-delete-button`,
+                hidden: (): boolean => isReadOnly,
+                icon: (): SemanticICONS =>  "trash alternate",
+                onClick: (e: SyntheticEvent, group: GroupsMemberInterface): void => {
+                    setDeletingGroup(group);
+                    setShowDeleteConfirmationModal(true);
+                },
+                popupText: (): string => t("common:delete"),
+                renderer: "semantic-icon"
+            }
+        ];
+
+        return actions;
+    };
+
+    /**
+     * Shows list placeholders.
+     *
+     * @returns Placeholders.
+     */
+    const showPlaceholders = (): ReactElement => {
+        // When the search returns empty.
path: features/admin.users.v1/components/user-groups-list.tsx
user: login: DonOmalVindula
body: Fixed with cb0ee2cf165319ca096aa44d358799060f08bbf9
created_at: 2025-03-21T11:17:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,493 @@
+/**
+ * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import Box from "@oxygen-ui/react/Box/Box";
+import { AdvancedSearchWithBasicFilters } from "@wso2is/admin.core.v1/components/advanced-search-with-basic-filters";
+import { getEmptyPlaceholderIllustrations } from "@wso2is/admin.core.v1/configs/ui";
+import { UIConstants } from "@wso2is/admin.core.v1/constants/ui-constants";
+import { userstoresConfig } from "@wso2is/admin.extensions.v1";
+import { updateGroupDetails } from "@wso2is/admin.groups.v1/api/groups";
+import { GroupsMemberInterface, PatchGroupDataInterface } from "@wso2is/admin.groups.v1/models/groups";
+import {
+    AlertLevels,
+    IdentifiableComponentInterface,
+    ProfileInfoInterface
+} from "@wso2is/core/models";
+import { addAlert } from "@wso2is/core/store";
+import {
+    ConfirmationModal,
+    DataTable,
+    EmphasizedSegment,
+    EmptyPlaceholder,
+    Heading,
+    LinkButton,
+    ListLayout,
+    PrimaryButton,
+    TableActionsInterface,
+    TableColumnInterface,
+    UserAvatar
+} from "@wso2is/react-components";
+import isEmpty from "lodash-es/isEmpty";
+import React, {
+    FunctionComponent,
+    ReactElement,
+    ReactNode,
+    SyntheticEvent,
+    useEffect,
+    useState
+} from "react";
+import { useTranslation } from "react-i18next";
+import { useDispatch } from "react-redux";
+import { Dispatch } from "redux";
+import { Divider, DropdownProps, Header, Icon, Label, PaginationProps, SemanticICONS } from "semantic-ui-react";
+import "./user-roles-list.scss";
+
+interface UserGroupsEditPropsInterface extends IdentifiableComponentInterface {
+    /**
+     * User profile
+     */
+    user: ProfileInfoInterface;
+    /**
+     * Is the component loading
+     */
+    isLoading?: boolean;
+    /**
+     * Is the component in read only mode
+     */
+    isReadOnly?: boolean;
+    /**
+     * Callback to open the add new group modal
+     */
+    handleOpenAddNewGroupModal: () => void;
+    /**
+     * Handle user update callback.
+     */
+    handleUserUpdate: (userId: string) => void;
+}
+
+export const UserGroupsListTable: FunctionComponent<UserGroupsEditPropsInterface> = (
+    props: UserGroupsEditPropsInterface
+): ReactElement => {
+
+    const {
+        user,
+        isLoading,
+        isReadOnly,
+        handleOpenAddNewGroupModal,
+        handleUserUpdate,
+        "data-componentid": componentId
+    } = props;
+
+    const { t } = useTranslation();
+
+    const dispatch: Dispatch = useDispatch();
+
+    const [ searchQuery, setSearchQuery ] = useState<string>("");
+    const [ listItemLimit, setListItemLimit ] = useState<number>(UIConstants.DEFAULT_RESOURCE_LIST_ITEM_LIMIT);
+    const [ listOffset, setListOffset ] = useState<number>(0);
+    const [ paginatedGroups, setPaginatedGroups ] = useState<GroupsMemberInterface[]>(undefined);
+    const [ triggerClearQuery, setTriggerClearQuery ] = useState<boolean>(false);
+    const [ showDeleteConfirmationModal, setShowDeleteConfirmationModal ] = useState<boolean>(false);
+    const [ deletingGroup, setDeletingGroup ] = useState<GroupsMemberInterface>(undefined);
+    const [ isDeleting, setDeleting ] = useState<boolean>(false);
+
+    const userGroupsList: GroupsMemberInterface[] = user?.groups;
+
+    /**
+     * Set initial selected roles options
+     */
+    useEffect(() => {
+        setGroupsPage(0, listItemLimit, userGroupsList, searchQuery);
+    }, [ user, searchQuery ]);
+
+    /**
+     * Util method to paginate retrieved groups  list.
+     *
+     * @param offsetValue - pagination offset value.
+     * @param itemLimit - pagination item limit.
+     * @param list - Role list.
+     */
+    const setGroupsPage = (
+        offsetValue: number,
+        itemLimit: number,
+        list: GroupsMemberInterface[],
+        searchQuery?: string
+    ) => {
+        if (!list) {
+            setPaginatedGroups([]);
+
+            return;
+        }
+
+        if (!isEmpty(searchQuery)) {
+            const filteredList: GroupsMemberInterface[] = list.filter((group: GroupsMemberInterface) => {
+                return group.display.toLowerCase().includes(searchQuery.toLowerCase());
+            });
+
+            setPaginatedGroups(filteredList?.slice(offsetValue, itemLimit + offsetValue));
+
+            return;
+        }
+
+        setPaginatedGroups(list?.slice(offsetValue, itemLimit + offsetValue));
+    };
+
+
+    const handlePaginationChange = (event: React.MouseEvent<HTMLAnchorElement>, data: PaginationProps) => {
+        const offsetValue: number = (data.activePage as number - 1) * listItemLimit;
+
+        setListOffset(offsetValue);
+        setGroupsPage(offsetValue, listItemLimit, userGroupsList);
+    };
+
+    const handleItemsPerPageDropdownChange = (event: React.MouseEvent<HTMLAnchorElement>, data: DropdownProps) => {
+        setListItemLimit(data.value as number);
+        setGroupsPage(listOffset, data.value as number, userGroupsList);
+    };
+
+    const handleSearchQueryClear = (): void => {
+        setTriggerClearQuery(!triggerClearQuery);
+        setSearchQuery("");
+    };
+
+    const resolveTotalPages = (): number => {
+        return Math.ceil(userGroupsList?.length / listItemLimit);
+    };
+
+    const unassignUserFromGroup = (group: GroupsMemberInterface) => {
+        const operationData: PatchGroupDataInterface = {
+            Operations: [ {
+                "op": "remove",
+                "path": `members[value eq ${user.id}]`
+            } ],
+            schemas: [ "urn:ietf:params:scim:api:messages:2.0:PatchOp" ]
+        };
+
+        updateGroupDetails(group.value, operationData)
+            .then(() => {
+                dispatch(addAlert({
+                    description: t("console:manage.features.groups.notifications.updateGroup.success.description"),
+                    level: AlertLevels.SUCCESS,
+                    message: t("console:manage.features.groups.notifications.updateGroup.success.message")
+                }));
+                handleUserUpdate(user.id);
+            }).catch(() => {
+                dispatch(addAlert({
+                    description: t("console:manage.features.groups.notifications.updateGroup.error.description"),
+                    level: AlertLevels.ERROR,
+                    message: t("console:manage.features.groups.notifications.updateGroup.error.message")
+                }));
+            }).finally(() => {
+                setDeleting(false);
+                setDeletingGroup(undefined);
+                setShowDeleteConfirmationModal(false);
+            });
+    };
+
+    /**
+     * Resolves data table columns.
+     *
+     * @returns the data table columns.
+     */
+    const resolveTableColumns = (): TableColumnInterface[] => {
+        const defaultColumns: TableColumnInterface[] = [
+            {
+                allowToggleVisibility: false,
+                dataIndex: "groupName",
+                id: "groupName",
+                key: "groupName",
+                render: (group: GroupsMemberInterface): ReactNode => {
+                    const userGroup: string[] = group?.display?.split("/");
+                    const userGroupName: string = userGroup.length === 1
+                        ? userGroup[0]
+                        : userGroup[1];
+
+                    return (
+                        <Header
+                            image
+                            as="h6"
+                            className="header-with-icon"
+                            data-componentid={ `${ componentId }-item-heading` }
+                        >
+                            <UserAvatar
+                                data-componentid="users-list-item-image"
+                                name={ group.display }
+                                size="mini"
+                                image={ user.profileUrl }
+                                spaced="right"
+                                data-suppress=""
+                            />
+                            <div>
+                                { userGroupName as ReactNode }
+                            </div>
+                        </Header>
+                    );
+                },
+                title: (
+                    <div className="pl-3">
+                        { t("user:updateUser.groups.editGroups.groupList.headers.1") }
+                    </div>
+                )
+            },
+            {
+                allowToggleVisibility: false,
+                dataIndex: "domain",
+                id: "domain",
+                key: "domain",
+                render: (group: GroupsMemberInterface): ReactNode => {
+                    const userGroup: string[] = group?.display?.split("/");
+                    const domain: string = userGroup.length === 1
+                        ? userstoresConfig.primaryUserstoreName
+                        : userGroup[0];
+
+                    return (
+                        <Header
+                            image
+                            as="h6"
+                            className="header-with-icon"
+                            data-componentid={ `${ componentId }-item-heading` }
+                        >
+                            <Label size="mini">
+                                { domain }
+                            </Label>
+                        </Header>
+                    );
+                },
+                title: (
+                    <div className="pl-3">
+                        { t("user:updateUser.groups.editGroups.groupList.headers.0") }
+                    </div>
+                )
+            }
+        ];
+
+        defaultColumns.push(
+            {
+                allowToggleVisibility: false,
+                dataIndex: "action",
+                id: "actions",
+                key: "actions",
+                textAlign: "right",
+                title: ""
+            }
+        );
+
+        return defaultColumns;
+    };
+
+    /**
+     * Resolves data table actions.
+     *
+     * @returns Table actions.
+     */
+    const resolveTableActions = (): TableActionsInterface[] => {
+        const actions: TableActionsInterface[] = [
+            {
+                "data-componentid": `${ componentId }-user-list-item-delete-button`,
+                "data-testid": `${ componentId }-user-list-item-delete-button`,
+                hidden: (): boolean => isReadOnly,
+                icon: (): SemanticICONS =>  "trash alternate",
+                onClick: (e: SyntheticEvent, group: GroupsMemberInterface): void => {
+                    setDeletingGroup(group);
+                    setShowDeleteConfirmationModal(true);
+                },
+                popupText: (): string => t("common:delete"),
+                renderer: "semantic-icon"
+            }
+        ];
+
+        return actions;
+    };
+
+    /**
+     * Shows list placeholders.
+     *
+     * @returns Placeholders.
+     */
+    const showPlaceholders = (): ReactElement => {
+        // When the search returns empty.
+        if (searchQuery) {
+            return (
+                <EmptyPlaceholder
+                    action={ (
+                        <LinkButton onClick={ handleSearchQueryClear }>
+                            { t("users:usersList.search.emptyResultPlaceholder.clearButton") }
+                        </LinkButton>
+                    ) }
+                    image={ getEmptyPlaceholderIllustrations().emptySearch }
+                    imageSize="tiny"
+                    data-testid="user-mgt-empty-groups-list"
+                    title={ t("user:updateUser.groups.editGroups." +
+                        "groupList.emptyListPlaceholder.title") }
+                    subtitle={ [
+                        t("roles:list.emptyPlaceholders.search.subtitles.0",
+                            { searchQuery: searchQuery }),
+                        t("roles:list.emptyPlaceholders.search.subtitles.1")
+                    ] }
+                />
+            );
+        }
+
+        if (paginatedGroups?.length === 0) {
+            return (
+                <EmptyPlaceholder
+                    data-testid="user-mgt-empty-groups-list"
+                    title={ t("user:updateUser.groups.editGroups." +
+                        "groupList.emptyListPlaceholder.title") }
+                    subtitle={ [
+                        t("user:updateUser.groups.editGroups." +
+                                "groupList.emptyListPlaceholder.subTitle.0"),
+                        t("user:updateUser.groups.editGroups." +
+                            "groupList.emptyListPlaceholder.subTitle.1"),
+                        t("user:updateUser.groups.editGroups." +
+                            "groupList.emptyListPlaceholder.subTitle.2")
+                    ] }
+                    action={
+                        !isReadOnly && (
+                            <PrimaryButton
+                                data-testid="user-mgt-empty-groups-list-assign-group-button"
+                                onClick={ handleOpenAddNewGroupModal }
+                                loading={ isLoading }
+                                disabled={ isLoading }
+                            >
+                                <Icon name="plus"/>
+                                { t("applicationRoles:roleGroups.assignGroup") }
+                            </PrimaryButton>
+                        )
+                    }
+                    image={ getEmptyPlaceholderIllustrations().emptyList }
+                    imageSize="tiny"
+                />
+            );
+        }
+
+        return null;
+    };
+
+    return (
+        <EmphasizedSegment
+            className="list-user-roles-section"
+            data-testid="user-mgt-groups-list"
+            padded="very"
+        >
+            <Box display="flex" justifyContent="space-between" alignItems="center">
+                {
+                    (!!searchQuery || paginatedGroups?.length > 0) &&  (
+                        <div>
+                            <Heading as="h4">
+                                { t("user:updateUser.groups.editGroups.heading") }
+                            </Heading>
+                            <Heading subHeading ellipsis as="h6">
+                                { t("user:updateUser.groups.editGroups.subHeading") }
+                            </Heading>
+                        </div>
+                    )
+                }
+                { !isReadOnly && (!!searchQuery || paginatedGroups?.length > 0) && (
+                    <PrimaryButton
+                        data-testid="user-mgt-groups-list-update-button"
+                        onClick={ handleOpenAddNewGroupModal }
+                    >
+                        <Icon name="plus"/>
+                        { t("applicationRoles:roleGroups.assignGroup") }
+                    </PrimaryButton>
+                ) }
+            </Box>
+            <Divider hidden/>
+            <ListLayout
+                advancedSearch={ (
+                    <AdvancedSearchWithBasicFilters
+                        data-testid="group-mgt-groups-list-advanced-search"
+                        onFilter={ (query: string) => setSearchQuery(query?.trim()) }
+                        disableSearchFilterDropdown
+                        filterAttributeOptions={ [] }
+                        placeholder={ t("console:manage.features.groups.advancedSearch.placeholder") }
+                        defaultSearchAttribute={ "" }
+                        defaultSearchOperator={ "" }
path: features/admin.users.v1/components/user-groups-list.tsx
user: login: DonOmalVindula
body: Fixed with cb0ee2cf165319ca096aa44d358799060f08bbf9
created_at: 2025-03-21T11:18:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,493 @@
+/**
+ * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import Box from "@oxygen-ui/react/Box/Box";
+import { AdvancedSearchWithBasicFilters } from "@wso2is/admin.core.v1/components/advanced-search-with-basic-filters";
+import { getEmptyPlaceholderIllustrations } from "@wso2is/admin.core.v1/configs/ui";
+import { UIConstants } from "@wso2is/admin.core.v1/constants/ui-constants";
+import { userstoresConfig } from "@wso2is/admin.extensions.v1";
+import { updateGroupDetails } from "@wso2is/admin.groups.v1/api/groups";
+import { GroupsMemberInterface, PatchGroupDataInterface } from "@wso2is/admin.groups.v1/models/groups";
+import {
+    AlertLevels,
+    IdentifiableComponentInterface,
+    ProfileInfoInterface
+} from "@wso2is/core/models";
+import { addAlert } from "@wso2is/core/store";
+import {
+    ConfirmationModal,
+    DataTable,
+    EmphasizedSegment,
+    EmptyPlaceholder,
+    Heading,
+    LinkButton,
+    ListLayout,
+    PrimaryButton,
+    TableActionsInterface,
+    TableColumnInterface,
+    UserAvatar
+} from "@wso2is/react-components";
+import isEmpty from "lodash-es/isEmpty";
+import React, {
+    FunctionComponent,
+    ReactElement,
+    ReactNode,
+    SyntheticEvent,
+    useEffect,
+    useState
+} from "react";
+import { useTranslation } from "react-i18next";
+import { useDispatch } from "react-redux";
+import { Dispatch } from "redux";
+import { Divider, DropdownProps, Header, Icon, Label, PaginationProps, SemanticICONS } from "semantic-ui-react";
+import "./user-roles-list.scss";
+
+interface UserGroupsEditPropsInterface extends IdentifiableComponentInterface {
+    /**
+     * User profile
+     */
+    user: ProfileInfoInterface;
+    /**
+     * Is the component loading
+     */
+    isLoading?: boolean;
+    /**
+     * Is the component in read only mode
+     */
+    isReadOnly?: boolean;
+    /**
+     * Callback to open the add new group modal
+     */
+    handleOpenAddNewGroupModal: () => void;
+    /**
+     * Handle user update callback.
+     */
+    handleUserUpdate: (userId: string) => void;
+}
+
+export const UserGroupsListTable: FunctionComponent<UserGroupsEditPropsInterface> = (
+    props: UserGroupsEditPropsInterface
+): ReactElement => {
+
+    const {
+        user,
+        isLoading,
+        isReadOnly,
+        handleOpenAddNewGroupModal,
+        handleUserUpdate,
+        "data-componentid": componentId
+    } = props;
+
+    const { t } = useTranslation();
+
+    const dispatch: Dispatch = useDispatch();
+
+    const [ searchQuery, setSearchQuery ] = useState<string>("");
+    const [ listItemLimit, setListItemLimit ] = useState<number>(UIConstants.DEFAULT_RESOURCE_LIST_ITEM_LIMIT);
+    const [ listOffset, setListOffset ] = useState<number>(0);
+    const [ paginatedGroups, setPaginatedGroups ] = useState<GroupsMemberInterface[]>(undefined);
+    const [ triggerClearQuery, setTriggerClearQuery ] = useState<boolean>(false);
+    const [ showDeleteConfirmationModal, setShowDeleteConfirmationModal ] = useState<boolean>(false);
+    const [ deletingGroup, setDeletingGroup ] = useState<GroupsMemberInterface>(undefined);
+    const [ isDeleting, setDeleting ] = useState<boolean>(false);
+
+    const userGroupsList: GroupsMemberInterface[] = user?.groups;
+
+    /**
+     * Set initial selected roles options
+     */
+    useEffect(() => {
+        setGroupsPage(0, listItemLimit, userGroupsList, searchQuery);
+    }, [ user, searchQuery ]);
+
+    /**
+     * Util method to paginate retrieved groups  list.
+     *
+     * @param offsetValue - pagination offset value.
+     * @param itemLimit - pagination item limit.
+     * @param list - Role list.
+     */
+    const setGroupsPage = (
+        offsetValue: number,
+        itemLimit: number,
+        list: GroupsMemberInterface[],
+        searchQuery?: string
+    ) => {
+        if (!list) {
+            setPaginatedGroups([]);
+
+            return;
+        }
+
+        if (!isEmpty(searchQuery)) {
+            const filteredList: GroupsMemberInterface[] = list.filter((group: GroupsMemberInterface) => {
+                return group.display.toLowerCase().includes(searchQuery.toLowerCase());
+            });
+
+            setPaginatedGroups(filteredList?.slice(offsetValue, itemLimit + offsetValue));
+
+            return;
+        }
+
+        setPaginatedGroups(list?.slice(offsetValue, itemLimit + offsetValue));
+    };
+
+
+    const handlePaginationChange = (event: React.MouseEvent<HTMLAnchorElement>, data: PaginationProps) => {
+        const offsetValue: number = (data.activePage as number - 1) * listItemLimit;
+
+        setListOffset(offsetValue);
+        setGroupsPage(offsetValue, listItemLimit, userGroupsList);
+    };
+
+    const handleItemsPerPageDropdownChange = (event: React.MouseEvent<HTMLAnchorElement>, data: DropdownProps) => {
+        setListItemLimit(data.value as number);
+        setGroupsPage(listOffset, data.value as number, userGroupsList);
+    };
+
+    const handleSearchQueryClear = (): void => {
+        setTriggerClearQuery(!triggerClearQuery);
+        setSearchQuery("");
+    };
+
+    const resolveTotalPages = (): number => {
+        return Math.ceil(userGroupsList?.length / listItemLimit);
+    };
+
+    const unassignUserFromGroup = (group: GroupsMemberInterface) => {
+        const operationData: PatchGroupDataInterface = {
+            Operations: [ {
+                "op": "remove",
+                "path": `members[value eq ${user.id}]`
+            } ],
+            schemas: [ "urn:ietf:params:scim:api:messages:2.0:PatchOp" ]
+        };
+
+        updateGroupDetails(group.value, operationData)
+            .then(() => {
+                dispatch(addAlert({
+                    description: t("console:manage.features.groups.notifications.updateGroup.success.description"),
+                    level: AlertLevels.SUCCESS,
+                    message: t("console:manage.features.groups.notifications.updateGroup.success.message")
+                }));
+                handleUserUpdate(user.id);
+            }).catch(() => {
+                dispatch(addAlert({
+                    description: t("console:manage.features.groups.notifications.updateGroup.error.description"),
+                    level: AlertLevels.ERROR,
+                    message: t("console:manage.features.groups.notifications.updateGroup.error.message")
+                }));
+            }).finally(() => {
+                setDeleting(false);
+                setDeletingGroup(undefined);
+                setShowDeleteConfirmationModal(false);
+            });
+    };
+
+    /**
+     * Resolves data table columns.
+     *
+     * @returns the data table columns.
+     */
+    const resolveTableColumns = (): TableColumnInterface[] => {
+        const defaultColumns: TableColumnInterface[] = [
+            {
+                allowToggleVisibility: false,
+                dataIndex: "groupName",
+                id: "groupName",
+                key: "groupName",
+                render: (group: GroupsMemberInterface): ReactNode => {
+                    const userGroup: string[] = group?.display?.split("/");
+                    const userGroupName: string = userGroup.length === 1
+                        ? userGroup[0]
+                        : userGroup[1];
+
+                    return (
+                        <Header
+                            image
+                            as="h6"
+                            className="header-with-icon"
+                            data-componentid={ `${ componentId }-item-heading` }
+                        >
+                            <UserAvatar
+                                data-componentid="users-list-item-image"
+                                name={ group.display }
+                                size="mini"
+                                image={ user.profileUrl }
+                                spaced="right"
+                                data-suppress=""
+                            />
+                            <div>
+                                { userGroupName as ReactNode }
+                            </div>
+                        </Header>
+                    );
+                },
+                title: (
+                    <div className="pl-3">
+                        { t("user:updateUser.groups.editGroups.groupList.headers.1") }
+                    </div>
+                )
+            },
+            {
+                allowToggleVisibility: false,
+                dataIndex: "domain",
+                id: "domain",
+                key: "domain",
+                render: (group: GroupsMemberInterface): ReactNode => {
+                    const userGroup: string[] = group?.display?.split("/");
+                    const domain: string = userGroup.length === 1
+                        ? userstoresConfig.primaryUserstoreName
+                        : userGroup[0];
+
+                    return (
+                        <Header
+                            image
+                            as="h6"
+                            className="header-with-icon"
+                            data-componentid={ `${ componentId }-item-heading` }
+                        >
+                            <Label size="mini">
+                                { domain }
+                            </Label>
+                        </Header>
+                    );
+                },
+                title: (
+                    <div className="pl-3">
+                        { t("user:updateUser.groups.editGroups.groupList.headers.0") }
+                    </div>
+                )
+            }
+        ];
+
+        defaultColumns.push(
+            {
+                allowToggleVisibility: false,
+                dataIndex: "action",
+                id: "actions",
+                key: "actions",
+                textAlign: "right",
+                title: ""
+            }
+        );
+
+        return defaultColumns;
+    };
+
+    /**
+     * Resolves data table actions.
+     *
+     * @returns Table actions.
+     */
+    const resolveTableActions = (): TableActionsInterface[] => {
+        const actions: TableActionsInterface[] = [
+            {
+                "data-componentid": `${ componentId }-user-list-item-delete-button`,
+                "data-testid": `${ componentId }-user-list-item-delete-button`,
+                hidden: (): boolean => isReadOnly,
+                icon: (): SemanticICONS =>  "trash alternate",
+                onClick: (e: SyntheticEvent, group: GroupsMemberInterface): void => {
+                    setDeletingGroup(group);
+                    setShowDeleteConfirmationModal(true);
+                },
+                popupText: (): string => t("common:delete"),
+                renderer: "semantic-icon"
+            }
+        ];
+
+        return actions;
+    };
+
+    /**
+     * Shows list placeholders.
+     *
+     * @returns Placeholders.
+     */
+    const showPlaceholders = (): ReactElement => {
+        // When the search returns empty.
+        if (searchQuery) {
+            return (
+                <EmptyPlaceholder
+                    action={ (
+                        <LinkButton onClick={ handleSearchQueryClear }>
+                            { t("users:usersList.search.emptyResultPlaceholder.clearButton") }
+                        </LinkButton>
+                    ) }
+                    image={ getEmptyPlaceholderIllustrations().emptySearch }
+                    imageSize="tiny"
+                    data-testid="user-mgt-empty-groups-list"
+                    title={ t("user:updateUser.groups.editGroups." +
+                        "groupList.emptyListPlaceholder.title") }
+                    subtitle={ [
+                        t("roles:list.emptyPlaceholders.search.subtitles.0",
+                            { searchQuery: searchQuery }),
+                        t("roles:list.emptyPlaceholders.search.subtitles.1")
+                    ] }
+                />
+            );
+        }
+
+        if (paginatedGroups?.length === 0) {
+            return (
+                <EmptyPlaceholder
+                    data-testid="user-mgt-empty-groups-list"
+                    title={ t("user:updateUser.groups.editGroups." +
+                        "groupList.emptyListPlaceholder.title") }
+                    subtitle={ [
+                        t("user:updateUser.groups.editGroups." +
+                                "groupList.emptyListPlaceholder.subTitle.0"),
+                        t("user:updateUser.groups.editGroups." +
+                            "groupList.emptyListPlaceholder.subTitle.1"),
+                        t("user:updateUser.groups.editGroups." +
+                            "groupList.emptyListPlaceholder.subTitle.2")
+                    ] }
+                    action={
+                        !isReadOnly && (
+                            <PrimaryButton
+                                data-testid="user-mgt-empty-groups-list-assign-group-button"
+                                onClick={ handleOpenAddNewGroupModal }
+                                loading={ isLoading }
+                                disabled={ isLoading }
+                            >
+                                <Icon name="plus"/>
+                                { t("applicationRoles:roleGroups.assignGroup") }
+                            </PrimaryButton>
+                        )
+                    }
+                    image={ getEmptyPlaceholderIllustrations().emptyList }
+                    imageSize="tiny"
+                />
+            );
+        }
+
+        return null;
+    };
+
+    return (
+        <EmphasizedSegment
+            className="list-user-roles-section"
+            data-testid="user-mgt-groups-list"
+            padded="very"
+        >
+            <Box display="flex" justifyContent="space-between" alignItems="center">
+                {
+                    (!!searchQuery || paginatedGroups?.length > 0) &&  (
+                        <div>
+                            <Heading as="h4">
+                                { t("user:updateUser.groups.editGroups.heading") }
+                            </Heading>
+                            <Heading subHeading ellipsis as="h6">
+                                { t("user:updateUser.groups.editGroups.subHeading") }
+                            </Heading>
+                        </div>
+                    )
+                }
+                { !isReadOnly && (!!searchQuery || paginatedGroups?.length > 0) && (
+                    <PrimaryButton
+                        data-testid="user-mgt-groups-list-update-button"
+                        onClick={ handleOpenAddNewGroupModal }
+                    >
+                        <Icon name="plus"/>
+                        { t("applicationRoles:roleGroups.assignGroup") }
+                    </PrimaryButton>
+                ) }
+            </Box>
+            <Divider hidden/>
+            <ListLayout
+                advancedSearch={ (
+                    <AdvancedSearchWithBasicFilters
+                        data-testid="group-mgt-groups-list-advanced-search"
+                        onFilter={ (query: string) => setSearchQuery(query?.trim()) }
+                        disableSearchFilterDropdown
+                        filterAttributeOptions={ [] }
+                        placeholder={ t("console:manage.features.groups.advancedSearch.placeholder") }
+                        defaultSearchAttribute={ "" }
+                        defaultSearchOperator={ "" }
+                        triggerClearQuery={ triggerClearQuery }
+                    />
+                ) }
+                currentListSize={ paginatedGroups?.length }
+                listItemLimit={ listItemLimit }
+                onItemsPerPageDropdownChange={ handleItemsPerPageDropdownChange }
+                data-componentid={ `${ componentId }-user-groups-list-layout` }
+                data-testid={ `${ componentId }-user-groups-list-layout` }
+                onPageChange={ handlePaginationChange }
+                showPagination={ true }
+                totalPages={ resolveTotalPages() }
+                totalListSize={ userGroupsList?.length }
+                showPaginationPageLimit={ !isReadOnly }
+                showTopActionPanel={ (!!searchQuery || userGroupsList?.length > 0) }
+            >
+                <DataTable<GroupsMemberInterface>
+                    isLoading={ isLoading }
+                    loadingStateOptions={ {
+                        count: UIConstants.DEFAULT_RESOURCE_LIST_ITEM_LIMIT,
+                        imageType: "circular"
+                    } }
+                    actions={ resolveTableActions() }
+                    columns={ resolveTableColumns() }
+                    data={ paginatedGroups }
+                    onRowClick={ () =>  null }
+                    placeholders={ showPlaceholders() }
+                    selectable={ false }
+                    showHeader={ true }
+                    data-testid={ componentId }
+                />
+            </ListLayout>
+            <ConfirmationModal
+                primaryActionLoading={ isDeleting }
+                data-testid={ `${ componentId }-confirmation-modal` }
+                data-componentid={ `${ componentId }-confirmation-modal` }
+                onClose={ (): void => setShowDeleteConfirmationModal(false) }
+                type="negative"
+                open={ showDeleteConfirmationModal }
+                primaryAction="Confirm"
+                secondaryAction="Cancel"
path: features/admin.users.v1/components/user-groups-list.tsx
user: login: DonOmalVindula
body: Fixed with cb0ee2cf165319ca096aa44d358799060f08bbf9
created_at: 2025-03-21T11:18:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,493 @@
+/**
+ * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import Box from "@oxygen-ui/react/Box/Box";
+import { AdvancedSearchWithBasicFilters } from "@wso2is/admin.core.v1/components/advanced-search-with-basic-filters";
+import { getEmptyPlaceholderIllustrations } from "@wso2is/admin.core.v1/configs/ui";
+import { UIConstants } from "@wso2is/admin.core.v1/constants/ui-constants";
+import { userstoresConfig } from "@wso2is/admin.extensions.v1";
+import { updateGroupDetails } from "@wso2is/admin.groups.v1/api/groups";
+import { GroupsMemberInterface, PatchGroupDataInterface } from "@wso2is/admin.groups.v1/models/groups";
+import {
+    AlertLevels,
+    IdentifiableComponentInterface,
+    ProfileInfoInterface
+} from "@wso2is/core/models";
+import { addAlert } from "@wso2is/core/store";
+import {
+    ConfirmationModal,
+    DataTable,
+    EmphasizedSegment,
+    EmptyPlaceholder,
+    Heading,
+    LinkButton,
+    ListLayout,
+    PrimaryButton,
+    TableActionsInterface,
+    TableColumnInterface,
+    UserAvatar
+} from "@wso2is/react-components";
+import isEmpty from "lodash-es/isEmpty";
+import React, {
+    FunctionComponent,
+    ReactElement,
+    ReactNode,
+    SyntheticEvent,
+    useEffect,
+    useState
+} from "react";
+import { useTranslation } from "react-i18next";
+import { useDispatch } from "react-redux";
+import { Dispatch } from "redux";
+import { Divider, DropdownProps, Header, Icon, Label, PaginationProps, SemanticICONS } from "semantic-ui-react";
+import "./user-roles-list.scss";
+
+interface UserGroupsEditPropsInterface extends IdentifiableComponentInterface {
+    /**
+     * User profile
+     */
+    user: ProfileInfoInterface;
+    /**
+     * Is the component loading
+     */
+    isLoading?: boolean;
+    /**
+     * Is the component in read only mode
+     */
+    isReadOnly?: boolean;
+    /**
+     * Callback to open the add new group modal
+     */
+    handleOpenAddNewGroupModal: () => void;
+    /**
+     * Handle user update callback.
+     */
+    handleUserUpdate: (userId: string) => void;
+}
+
+export const UserGroupsListTable: FunctionComponent<UserGroupsEditPropsInterface> = (
+    props: UserGroupsEditPropsInterface
+): ReactElement => {
+
+    const {
+        user,
+        isLoading,
+        isReadOnly,
+        handleOpenAddNewGroupModal,
+        handleUserUpdate,
+        "data-componentid": componentId
+    } = props;
+
+    const { t } = useTranslation();
+
+    const dispatch: Dispatch = useDispatch();
+
+    const [ searchQuery, setSearchQuery ] = useState<string>("");
+    const [ listItemLimit, setListItemLimit ] = useState<number>(UIConstants.DEFAULT_RESOURCE_LIST_ITEM_LIMIT);
+    const [ listOffset, setListOffset ] = useState<number>(0);
+    const [ paginatedGroups, setPaginatedGroups ] = useState<GroupsMemberInterface[]>(undefined);
+    const [ triggerClearQuery, setTriggerClearQuery ] = useState<boolean>(false);
+    const [ showDeleteConfirmationModal, setShowDeleteConfirmationModal ] = useState<boolean>(false);
+    const [ deletingGroup, setDeletingGroup ] = useState<GroupsMemberInterface>(undefined);
+    const [ isDeleting, setDeleting ] = useState<boolean>(false);
+
+    const userGroupsList: GroupsMemberInterface[] = user?.groups;
+
+    /**
+     * Set initial selected roles options
+     */
+    useEffect(() => {
+        setGroupsPage(0, listItemLimit, userGroupsList, searchQuery);
+    }, [ user, searchQuery ]);
+
+    /**
+     * Util method to paginate retrieved groups  list.
+     *
+     * @param offsetValue - pagination offset value.
+     * @param itemLimit - pagination item limit.
+     * @param list - Role list.
+     */
+    const setGroupsPage = (
+        offsetValue: number,
+        itemLimit: number,
+        list: GroupsMemberInterface[],
+        searchQuery?: string
+    ) => {
+        if (!list) {
+            setPaginatedGroups([]);
+
+            return;
+        }
+
+        if (!isEmpty(searchQuery)) {
+            const filteredList: GroupsMemberInterface[] = list.filter((group: GroupsMemberInterface) => {
+                return group.display.toLowerCase().includes(searchQuery.toLowerCase());
+            });
+
+            setPaginatedGroups(filteredList?.slice(offsetValue, itemLimit + offsetValue));
+
+            return;
+        }
+
+        setPaginatedGroups(list?.slice(offsetValue, itemLimit + offsetValue));
+    };
+
+
+    const handlePaginationChange = (event: React.MouseEvent<HTMLAnchorElement>, data: PaginationProps) => {
+        const offsetValue: number = (data.activePage as number - 1) * listItemLimit;
+
+        setListOffset(offsetValue);
+        setGroupsPage(offsetValue, listItemLimit, userGroupsList);
+    };
+
+    const handleItemsPerPageDropdownChange = (event: React.MouseEvent<HTMLAnchorElement>, data: DropdownProps) => {
+        setListItemLimit(data.value as number);
+        setGroupsPage(listOffset, data.value as number, userGroupsList);
+    };
+
+    const handleSearchQueryClear = (): void => {
+        setTriggerClearQuery(!triggerClearQuery);
+        setSearchQuery("");
+    };
+
+    const resolveTotalPages = (): number => {
+        return Math.ceil(userGroupsList?.length / listItemLimit);
+    };
+
+    const unassignUserFromGroup = (group: GroupsMemberInterface) => {
+        const operationData: PatchGroupDataInterface = {
+            Operations: [ {
+                "op": "remove",
+                "path": `members[value eq ${user.id}]`
+            } ],
+            schemas: [ "urn:ietf:params:scim:api:messages:2.0:PatchOp" ]
+        };
+
+        updateGroupDetails(group.value, operationData)
+            .then(() => {
+                dispatch(addAlert({
+                    description: t("console:manage.features.groups.notifications.updateGroup.success.description"),
+                    level: AlertLevels.SUCCESS,
+                    message: t("console:manage.features.groups.notifications.updateGroup.success.message")
+                }));
+                handleUserUpdate(user.id);
+            }).catch(() => {
+                dispatch(addAlert({
+                    description: t("console:manage.features.groups.notifications.updateGroup.error.description"),
+                    level: AlertLevels.ERROR,
+                    message: t("console:manage.features.groups.notifications.updateGroup.error.message")
+                }));
+            }).finally(() => {
+                setDeleting(false);
+                setDeletingGroup(undefined);
+                setShowDeleteConfirmationModal(false);
+            });
+    };
+
+    /**
+     * Resolves data table columns.
+     *
+     * @returns the data table columns.
+     */
+    const resolveTableColumns = (): TableColumnInterface[] => {
+        const defaultColumns: TableColumnInterface[] = [
+            {
+                allowToggleVisibility: false,
+                dataIndex: "groupName",
+                id: "groupName",
+                key: "groupName",
+                render: (group: GroupsMemberInterface): ReactNode => {
+                    const userGroup: string[] = group?.display?.split("/");
+                    const userGroupName: string = userGroup.length === 1
+                        ? userGroup[0]
+                        : userGroup[1];
+
+                    return (
+                        <Header
+                            image
+                            as="h6"
+                            className="header-with-icon"
+                            data-componentid={ `${ componentId }-item-heading` }
+                        >
+                            <UserAvatar
+                                data-componentid="users-list-item-image"
+                                name={ group.display }
+                                size="mini"
+                                image={ user.profileUrl }
+                                spaced="right"
+                                data-suppress=""
+                            />
+                            <div>
+                                { userGroupName as ReactNode }
+                            </div>
+                        </Header>
+                    );
+                },
+                title: (
+                    <div className="pl-3">
+                        { t("user:updateUser.groups.editGroups.groupList.headers.1") }
+                    </div>
+                )
+            },
+            {
+                allowToggleVisibility: false,
+                dataIndex: "domain",
+                id: "domain",
+                key: "domain",
+                render: (group: GroupsMemberInterface): ReactNode => {
+                    const userGroup: string[] = group?.display?.split("/");
+                    const domain: string = userGroup.length === 1
+                        ? userstoresConfig.primaryUserstoreName
+                        : userGroup[0];
+
+                    return (
+                        <Header
+                            image
+                            as="h6"
+                            className="header-with-icon"
+                            data-componentid={ `${ componentId }-item-heading` }
+                        >
+                            <Label size="mini">
+                                { domain }
+                            </Label>
+                        </Header>
+                    );
+                },
+                title: (
+                    <div className="pl-3">
+                        { t("user:updateUser.groups.editGroups.groupList.headers.0") }
+                    </div>
+                )
+            }
+        ];
+
+        defaultColumns.push(
+            {
+                allowToggleVisibility: false,
+                dataIndex: "action",
+                id: "actions",
+                key: "actions",
+                textAlign: "right",
+                title: ""
+            }
+        );
+
+        return defaultColumns;
+    };
+
+    /**
+     * Resolves data table actions.
+     *
+     * @returns Table actions.
+     */
+    const resolveTableActions = (): TableActionsInterface[] => {
+        const actions: TableActionsInterface[] = [
+            {
+                "data-componentid": `${ componentId }-user-list-item-delete-button`,
+                "data-testid": `${ componentId }-user-list-item-delete-button`,
+                hidden: (): boolean => isReadOnly,
+                icon: (): SemanticICONS =>  "trash alternate",
+                onClick: (e: SyntheticEvent, group: GroupsMemberInterface): void => {
+                    setDeletingGroup(group);
+                    setShowDeleteConfirmationModal(true);
+                },
+                popupText: (): string => t("common:delete"),
+                renderer: "semantic-icon"
+            }
+        ];
+
+        return actions;
+    };
+
+    /**
+     * Shows list placeholders.
+     *
+     * @returns Placeholders.
+     */
+    const showPlaceholders = (): ReactElement => {
+        // When the search returns empty.
+        if (searchQuery) {
+            return (
+                <EmptyPlaceholder
+                    action={ (
+                        <LinkButton onClick={ handleSearchQueryClear }>
+                            { t("users:usersList.search.emptyResultPlaceholder.clearButton") }
+                        </LinkButton>
+                    ) }
+                    image={ getEmptyPlaceholderIllustrations().emptySearch }
+                    imageSize="tiny"
+                    data-testid="user-mgt-empty-groups-list"
+                    title={ t("user:updateUser.groups.editGroups." +
+                        "groupList.emptyListPlaceholder.title") }
+                    subtitle={ [
+                        t("roles:list.emptyPlaceholders.search.subtitles.0",
+                            { searchQuery: searchQuery }),
+                        t("roles:list.emptyPlaceholders.search.subtitles.1")
+                    ] }
+                />
+            );
+        }
+
+        if (paginatedGroups?.length === 0) {
+            return (
+                <EmptyPlaceholder
+                    data-testid="user-mgt-empty-groups-list"
+                    title={ t("user:updateUser.groups.editGroups." +
+                        "groupList.emptyListPlaceholder.title") }
+                    subtitle={ [
+                        t("user:updateUser.groups.editGroups." +
+                                "groupList.emptyListPlaceholder.subTitle.0"),
+                        t("user:updateUser.groups.editGroups." +
+                            "groupList.emptyListPlaceholder.subTitle.1"),
+                        t("user:updateUser.groups.editGroups." +
+                            "groupList.emptyListPlaceholder.subTitle.2")
+                    ] }
+                    action={
+                        !isReadOnly && (
+                            <PrimaryButton
+                                data-testid="user-mgt-empty-groups-list-assign-group-button"
+                                onClick={ handleOpenAddNewGroupModal }
+                                loading={ isLoading }
+                                disabled={ isLoading }
+                            >
+                                <Icon name="plus"/>
+                                { t("applicationRoles:roleGroups.assignGroup") }
+                            </PrimaryButton>
+                        )
+                    }
+                    image={ getEmptyPlaceholderIllustrations().emptyList }
+                    imageSize="tiny"
+                />
+            );
+        }
+
+        return null;
+    };
+
+    return (
+        <EmphasizedSegment
+            className="list-user-roles-section"
+            data-testid="user-mgt-groups-list"
+            padded="very"
+        >
+            <Box display="flex" justifyContent="space-between" alignItems="center">
+                {
+                    (!!searchQuery || paginatedGroups?.length > 0) &&  (
+                        <div>
+                            <Heading as="h4">
+                                { t("user:updateUser.groups.editGroups.heading") }
+                            </Heading>
+                            <Heading subHeading ellipsis as="h6">
+                                { t("user:updateUser.groups.editGroups.subHeading") }
+                            </Heading>
+                        </div>
+                    )
+                }
+                { !isReadOnly && (!!searchQuery || paginatedGroups?.length > 0) && (
+                    <PrimaryButton
+                        data-testid="user-mgt-groups-list-update-button"
+                        onClick={ handleOpenAddNewGroupModal }
+                    >
+                        <Icon name="plus"/>
+                        { t("applicationRoles:roleGroups.assignGroup") }
+                    </PrimaryButton>
+                ) }
+            </Box>
+            <Divider hidden/>
+            <ListLayout
+                advancedSearch={ (
+                    <AdvancedSearchWithBasicFilters
+                        data-testid="group-mgt-groups-list-advanced-search"
+                        onFilter={ (query: string) => setSearchQuery(query?.trim()) }
+                        disableSearchFilterDropdown
+                        filterAttributeOptions={ [] }
+                        placeholder={ t("console:manage.features.groups.advancedSearch.placeholder") }
+                        defaultSearchAttribute={ "" }
+                        defaultSearchOperator={ "" }
+                        triggerClearQuery={ triggerClearQuery }
+                    />
+                ) }
+                currentListSize={ paginatedGroups?.length }
+                listItemLimit={ listItemLimit }
+                onItemsPerPageDropdownChange={ handleItemsPerPageDropdownChange }
+                data-componentid={ `${ componentId }-user-groups-list-layout` }
+                data-testid={ `${ componentId }-user-groups-list-layout` }
+                onPageChange={ handlePaginationChange }
+                showPagination={ true }
+                totalPages={ resolveTotalPages() }
+                totalListSize={ userGroupsList?.length }
+                showPaginationPageLimit={ !isReadOnly }
+                showTopActionPanel={ (!!searchQuery || userGroupsList?.length > 0) }
+            >
+                <DataTable<GroupsMemberInterface>
+                    isLoading={ isLoading }
+                    loadingStateOptions={ {
+                        count: UIConstants.DEFAULT_RESOURCE_LIST_ITEM_LIMIT,
+                        imageType: "circular"
+                    } }
+                    actions={ resolveTableActions() }
+                    columns={ resolveTableColumns() }
+                    data={ paginatedGroups }
+                    onRowClick={ () =>  null }
+                    placeholders={ showPlaceholders() }
+                    selectable={ false }
+                    showHeader={ true }
+                    data-testid={ componentId }
+                />
+            </ListLayout>
+            <ConfirmationModal
+                primaryActionLoading={ isDeleting }
+                data-testid={ `${ componentId }-confirmation-modal` }
+                data-componentid={ `${ componentId }-confirmation-modal` }
+                onClose={ (): void => setShowDeleteConfirmationModal(false) }
+                type="negative"
+                open={ showDeleteConfirmationModal }
+                primaryAction="Confirm"
+                secondaryAction="Cancel"
+                onSecondaryActionClick={ (): void => {
+                    setShowDeleteConfirmationModal(false);
+                } }
+                onPrimaryActionClick={ (): void => {
+                    setDeleting(true);
+                    unassignUserFromGroup(deletingGroup);
+                } }
+                closeOnDimmerClick={ false }
+            >
+                <ConfirmationModal.Header
+                    data-testid={ `${ componentId }-confirmation-modal-header` }
+                    data-componentid={ `${ componentId }-confirmation-modal-header` }
path: features/admin.users.v1/components/user-groups-list.tsx
user: login: DonOmalVindula
body: Fixed with cb0ee2cf165319ca096aa44d358799060f08bbf9
created_at: 2025-03-21T11:18:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,493 @@
+/**
+ * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import Box from "@oxygen-ui/react/Box/Box";
+import { AdvancedSearchWithBasicFilters } from "@wso2is/admin.core.v1/components/advanced-search-with-basic-filters";
+import { getEmptyPlaceholderIllustrations } from "@wso2is/admin.core.v1/configs/ui";
+import { UIConstants } from "@wso2is/admin.core.v1/constants/ui-constants";
+import { userstoresConfig } from "@wso2is/admin.extensions.v1";
+import { updateGroupDetails } from "@wso2is/admin.groups.v1/api/groups";
+import { GroupsMemberInterface, PatchGroupDataInterface } from "@wso2is/admin.groups.v1/models/groups";
+import {
+    AlertLevels,
+    IdentifiableComponentInterface,
+    ProfileInfoInterface
+} from "@wso2is/core/models";
+import { addAlert } from "@wso2is/core/store";
+import {
+    ConfirmationModal,
+    DataTable,
+    EmphasizedSegment,
+    EmptyPlaceholder,
+    Heading,
+    LinkButton,
+    ListLayout,
+    PrimaryButton,
+    TableActionsInterface,
+    TableColumnInterface,
+    UserAvatar
+} from "@wso2is/react-components";
+import isEmpty from "lodash-es/isEmpty";
+import React, {
+    FunctionComponent,
+    ReactElement,
+    ReactNode,
+    SyntheticEvent,
+    useEffect,
+    useState
+} from "react";
+import { useTranslation } from "react-i18next";
+import { useDispatch } from "react-redux";
+import { Dispatch } from "redux";
+import { Divider, DropdownProps, Header, Icon, Label, PaginationProps, SemanticICONS } from "semantic-ui-react";
+import "./user-roles-list.scss";
+
+interface UserGroupsEditPropsInterface extends IdentifiableComponentInterface {
+    /**
+     * User profile
+     */
+    user: ProfileInfoInterface;
+    /**
+     * Is the component loading
+     */
+    isLoading?: boolean;
+    /**
+     * Is the component in read only mode
+     */
+    isReadOnly?: boolean;
+    /**
+     * Callback to open the add new group modal
+     */
+    handleOpenAddNewGroupModal: () => void;
+    /**
+     * Handle user update callback.
+     */
+    handleUserUpdate: (userId: string) => void;
+}
+
+export const UserGroupsListTable: FunctionComponent<UserGroupsEditPropsInterface> = (
+    props: UserGroupsEditPropsInterface
+): ReactElement => {
+
+    const {
+        user,
+        isLoading,
+        isReadOnly,
+        handleOpenAddNewGroupModal,
+        handleUserUpdate,
+        "data-componentid": componentId
+    } = props;
+
+    const { t } = useTranslation();
+
+    const dispatch: Dispatch = useDispatch();
+
+    const [ searchQuery, setSearchQuery ] = useState<string>("");
+    const [ listItemLimit, setListItemLimit ] = useState<number>(UIConstants.DEFAULT_RESOURCE_LIST_ITEM_LIMIT);
+    const [ listOffset, setListOffset ] = useState<number>(0);
+    const [ paginatedGroups, setPaginatedGroups ] = useState<GroupsMemberInterface[]>(undefined);
+    const [ triggerClearQuery, setTriggerClearQuery ] = useState<boolean>(false);
+    const [ showDeleteConfirmationModal, setShowDeleteConfirmationModal ] = useState<boolean>(false);
+    const [ deletingGroup, setDeletingGroup ] = useState<GroupsMemberInterface>(undefined);
+    const [ isDeleting, setDeleting ] = useState<boolean>(false);
+
+    const userGroupsList: GroupsMemberInterface[] = user?.groups;
+
+    /**
+     * Set initial selected roles options
+     */
+    useEffect(() => {
+        setGroupsPage(0, listItemLimit, userGroupsList, searchQuery);
+    }, [ user, searchQuery ]);
+
+    /**
+     * Util method to paginate retrieved groups  list.
+     *
+     * @param offsetValue - pagination offset value.
+     * @param itemLimit - pagination item limit.
+     * @param list - Role list.
+     */
+    const setGroupsPage = (
+        offsetValue: number,
+        itemLimit: number,
+        list: GroupsMemberInterface[],
+        searchQuery?: string
+    ) => {
+        if (!list) {
+            setPaginatedGroups([]);
+
+            return;
+        }
+
+        if (!isEmpty(searchQuery)) {
+            const filteredList: GroupsMemberInterface[] = list.filter((group: GroupsMemberInterface) => {
+                return group.display.toLowerCase().includes(searchQuery.toLowerCase());
+            });
+
+            setPaginatedGroups(filteredList?.slice(offsetValue, itemLimit + offsetValue));
+
+            return;
+        }
+
+        setPaginatedGroups(list?.slice(offsetValue, itemLimit + offsetValue));
+    };
+
+
+    const handlePaginationChange = (event: React.MouseEvent<HTMLAnchorElement>, data: PaginationProps) => {
+        const offsetValue: number = (data.activePage as number - 1) * listItemLimit;
+
+        setListOffset(offsetValue);
+        setGroupsPage(offsetValue, listItemLimit, userGroupsList);
+    };
+
+    const handleItemsPerPageDropdownChange = (event: React.MouseEvent<HTMLAnchorElement>, data: DropdownProps) => {
+        setListItemLimit(data.value as number);
+        setGroupsPage(listOffset, data.value as number, userGroupsList);
+    };
+
+    const handleSearchQueryClear = (): void => {
+        setTriggerClearQuery(!triggerClearQuery);
+        setSearchQuery("");
+    };
+
+    const resolveTotalPages = (): number => {
+        return Math.ceil(userGroupsList?.length / listItemLimit);
+    };
+
+    const unassignUserFromGroup = (group: GroupsMemberInterface) => {
+        const operationData: PatchGroupDataInterface = {
+            Operations: [ {
+                "op": "remove",
+                "path": `members[value eq ${user.id}]`
+            } ],
+            schemas: [ "urn:ietf:params:scim:api:messages:2.0:PatchOp" ]
+        };
+
+        updateGroupDetails(group.value, operationData)
+            .then(() => {
+                dispatch(addAlert({
+                    description: t("console:manage.features.groups.notifications.updateGroup.success.description"),
+                    level: AlertLevels.SUCCESS,
+                    message: t("console:manage.features.groups.notifications.updateGroup.success.message")
+                }));
+                handleUserUpdate(user.id);
+            }).catch(() => {
+                dispatch(addAlert({
+                    description: t("console:manage.features.groups.notifications.updateGroup.error.description"),
+                    level: AlertLevels.ERROR,
+                    message: t("console:manage.features.groups.notifications.updateGroup.error.message")
+                }));
+            }).finally(() => {
+                setDeleting(false);
+                setDeletingGroup(undefined);
+                setShowDeleteConfirmationModal(false);
+            });
+    };
+
+    /**
+     * Resolves data table columns.
+     *
+     * @returns the data table columns.
+     */
+    const resolveTableColumns = (): TableColumnInterface[] => {
+        const defaultColumns: TableColumnInterface[] = [
+            {
+                allowToggleVisibility: false,
+                dataIndex: "groupName",
+                id: "groupName",
+                key: "groupName",
+                render: (group: GroupsMemberInterface): ReactNode => {
+                    const userGroup: string[] = group?.display?.split("/");
+                    const userGroupName: string = userGroup.length === 1
+                        ? userGroup[0]
+                        : userGroup[1];
+
+                    return (
+                        <Header
+                            image
+                            as="h6"
+                            className="header-with-icon"
+                            data-componentid={ `${ componentId }-item-heading` }
+                        >
+                            <UserAvatar
+                                data-componentid="users-list-item-image"
+                                name={ group.display }
+                                size="mini"
+                                image={ user.profileUrl }
+                                spaced="right"
+                                data-suppress=""
+                            />
+                            <div>
+                                { userGroupName as ReactNode }
+                            </div>
+                        </Header>
+                    );
+                },
+                title: (
+                    <div className="pl-3">
+                        { t("user:updateUser.groups.editGroups.groupList.headers.1") }
+                    </div>
+                )
+            },
+            {
+                allowToggleVisibility: false,
+                dataIndex: "domain",
+                id: "domain",
+                key: "domain",
+                render: (group: GroupsMemberInterface): ReactNode => {
+                    const userGroup: string[] = group?.display?.split("/");
+                    const domain: string = userGroup.length === 1
+                        ? userstoresConfig.primaryUserstoreName
+                        : userGroup[0];
+
+                    return (
+                        <Header
+                            image
+                            as="h6"
+                            className="header-with-icon"
+                            data-componentid={ `${ componentId }-item-heading` }
+                        >
+                            <Label size="mini">
+                                { domain }
+                            </Label>
+                        </Header>
+                    );
+                },
+                title: (
+                    <div className="pl-3">
+                        { t("user:updateUser.groups.editGroups.groupList.headers.0") }
+                    </div>
+                )
+            }
+        ];
+
+        defaultColumns.push(
+            {
+                allowToggleVisibility: false,
+                dataIndex: "action",
+                id: "actions",
+                key: "actions",
+                textAlign: "right",
+                title: ""
+            }
+        );
+
+        return defaultColumns;
+    };
+
+    /**
+     * Resolves data table actions.
+     *
+     * @returns Table actions.
+     */
+    const resolveTableActions = (): TableActionsInterface[] => {
+        const actions: TableActionsInterface[] = [
+            {
+                "data-componentid": `${ componentId }-user-list-item-delete-button`,
+                "data-testid": `${ componentId }-user-list-item-delete-button`,
+                hidden: (): boolean => isReadOnly,
+                icon: (): SemanticICONS =>  "trash alternate",
+                onClick: (e: SyntheticEvent, group: GroupsMemberInterface): void => {
+                    setDeletingGroup(group);
+                    setShowDeleteConfirmationModal(true);
+                },
+                popupText: (): string => t("common:delete"),
+                renderer: "semantic-icon"
+            }
+        ];
+
+        return actions;
+    };
+
+    /**
+     * Shows list placeholders.
+     *
+     * @returns Placeholders.
+     */
+    const showPlaceholders = (): ReactElement => {
+        // When the search returns empty.
+        if (searchQuery) {
+            return (
+                <EmptyPlaceholder
+                    action={ (
+                        <LinkButton onClick={ handleSearchQueryClear }>
+                            { t("users:usersList.search.emptyResultPlaceholder.clearButton") }
+                        </LinkButton>
+                    ) }
+                    image={ getEmptyPlaceholderIllustrations().emptySearch }
+                    imageSize="tiny"
+                    data-testid="user-mgt-empty-groups-list"
+                    title={ t("user:updateUser.groups.editGroups." +
+                        "groupList.emptyListPlaceholder.title") }
+                    subtitle={ [
+                        t("roles:list.emptyPlaceholders.search.subtitles.0",
+                            { searchQuery: searchQuery }),
+                        t("roles:list.emptyPlaceholders.search.subtitles.1")
+                    ] }
+                />
+            );
+        }
+
+        if (paginatedGroups?.length === 0) {
+            return (
+                <EmptyPlaceholder
+                    data-testid="user-mgt-empty-groups-list"
+                    title={ t("user:updateUser.groups.editGroups." +
+                        "groupList.emptyListPlaceholder.title") }
+                    subtitle={ [
+                        t("user:updateUser.groups.editGroups." +
+                                "groupList.emptyListPlaceholder.subTitle.0"),
+                        t("user:updateUser.groups.editGroups." +
+                            "groupList.emptyListPlaceholder.subTitle.1"),
+                        t("user:updateUser.groups.editGroups." +
+                            "groupList.emptyListPlaceholder.subTitle.2")
+                    ] }
+                    action={
+                        !isReadOnly && (
+                            <PrimaryButton
+                                data-testid="user-mgt-empty-groups-list-assign-group-button"
+                                onClick={ handleOpenAddNewGroupModal }
+                                loading={ isLoading }
+                                disabled={ isLoading }
+                            >
+                                <Icon name="plus"/>
+                                { t("applicationRoles:roleGroups.assignGroup") }
+                            </PrimaryButton>
+                        )
+                    }
+                    image={ getEmptyPlaceholderIllustrations().emptyList }
+                    imageSize="tiny"
+                />
+            );
+        }
+
+        return null;
+    };
+
+    return (
+        <EmphasizedSegment
+            className="list-user-roles-section"
+            data-testid="user-mgt-groups-list"
+            padded="very"
+        >
+            <Box display="flex" justifyContent="space-between" alignItems="center">
+                {
+                    (!!searchQuery || paginatedGroups?.length > 0) &&  (
+                        <div>
+                            <Heading as="h4">
+                                { t("user:updateUser.groups.editGroups.heading") }
+                            </Heading>
+                            <Heading subHeading ellipsis as="h6">
+                                { t("user:updateUser.groups.editGroups.subHeading") }
+                            </Heading>
+                        </div>
+                    )
+                }
+                { !isReadOnly && (!!searchQuery || paginatedGroups?.length > 0) && (
+                    <PrimaryButton
+                        data-testid="user-mgt-groups-list-update-button"
+                        onClick={ handleOpenAddNewGroupModal }
+                    >
+                        <Icon name="plus"/>
+                        { t("applicationRoles:roleGroups.assignGroup") }
+                    </PrimaryButton>
+                ) }
+            </Box>
+            <Divider hidden/>
+            <ListLayout
+                advancedSearch={ (
+                    <AdvancedSearchWithBasicFilters
+                        data-testid="group-mgt-groups-list-advanced-search"
+                        onFilter={ (query: string) => setSearchQuery(query?.trim()) }
+                        disableSearchFilterDropdown
+                        filterAttributeOptions={ [] }
+                        placeholder={ t("console:manage.features.groups.advancedSearch.placeholder") }
+                        defaultSearchAttribute={ "" }
+                        defaultSearchOperator={ "" }
+                        triggerClearQuery={ triggerClearQuery }
+                    />
+                ) }
+                currentListSize={ paginatedGroups?.length }
+                listItemLimit={ listItemLimit }
+                onItemsPerPageDropdownChange={ handleItemsPerPageDropdownChange }
+                data-componentid={ `${ componentId }-user-groups-list-layout` }
+                data-testid={ `${ componentId }-user-groups-list-layout` }
+                onPageChange={ handlePaginationChange }
+                showPagination={ true }
+                totalPages={ resolveTotalPages() }
+                totalListSize={ userGroupsList?.length }
+                showPaginationPageLimit={ !isReadOnly }
+                showTopActionPanel={ (!!searchQuery || userGroupsList?.length > 0) }
+            >
+                <DataTable<GroupsMemberInterface>
+                    isLoading={ isLoading }
+                    loadingStateOptions={ {
+                        count: UIConstants.DEFAULT_RESOURCE_LIST_ITEM_LIMIT,
+                        imageType: "circular"
+                    } }
+                    actions={ resolveTableActions() }
+                    columns={ resolveTableColumns() }
+                    data={ paginatedGroups }
+                    onRowClick={ () =>  null }
+                    placeholders={ showPlaceholders() }
+                    selectable={ false }
+                    showHeader={ true }
+                    data-testid={ componentId }
+                />
+            </ListLayout>
+            <ConfirmationModal
+                primaryActionLoading={ isDeleting }
+                data-testid={ `${ componentId }-confirmation-modal` }
+                data-componentid={ `${ componentId }-confirmation-modal` }
+                onClose={ (): void => setShowDeleteConfirmationModal(false) }
+                type="negative"
+                open={ showDeleteConfirmationModal }
+                primaryAction="Confirm"
+                secondaryAction="Cancel"
+                onSecondaryActionClick={ (): void => {
+                    setShowDeleteConfirmationModal(false);
+                } }
+                onPrimaryActionClick={ (): void => {
+                    setDeleting(true);
+                    unassignUserFromGroup(deletingGroup);
+                } }
+                closeOnDimmerClick={ false }
+            >
+                <ConfirmationModal.Header
+                    data-testid={ `${ componentId }-confirmation-modal-header` }
+                    data-componentid={ `${ componentId }-confirmation-modal-header` }
+                >
+                    { t("users:confirmations.unassignGroup.header") }
+                </ConfirmationModal.Header>
+                <ConfirmationModal.Content
+                    data-testid={ `${ componentId }-confirmation-modal-content` }
+                    data-componentid={ `${ componentId }-confirmation-modal-content` }
+                >
+                    { t("users:confirmations.unassignGroup.content") }
+                </ConfirmationModal.Content>
+            </ConfirmationModal>
+        </EmphasizedSegment>
+    );
+};
+
+/**
+ * Default props for user groups list tab component.
+ */
+UserGroupsListTable.defaultProps = {
path: features/admin.users.v1/components/user-groups-list.tsx
user: login: DonOmalVindula
body: Fixed with cb0ee2cf165319ca096aa44d358799060f08bbf9
created_at: 2025-03-21T11:18:18Z
author_association: CONTRIBUTOR

PR comments:
user: login: pavinduLakshan
created_at: 2025-03-20T15:45:46Z
body: shall we add a screenshot of before and after for record purposes?
author_association: MEMBER
user: login: wso2-jenkins-bot
created_at: 2025-03-21T11:14:14Z
body: <h3>🦋 Changeset detected</h3><p><b>The changes in this PR will be included in the next version bump.</b></p><p>Not sure what this means? <a href="https://github.com/changesets/changesets/blob/master/docs/adding-a-changeset.md">Click here to learn what changesets are</a>.</p>
author_association: CONTRIBUTOR
user: login: DonOmalVindula
created_at: 2025-03-21T11:19:14Z
body: > shall we add a screenshot of before and after for record purposes?

Added - https://github.com/wso2/identity-apps/pull/7929#issue-2935252117
author_association: CONTRIBUTOR
user: login: codecov[bot]
created_at: 2025-03-21T11:24:54Z
body: ## [Codecov](https://app.codecov.io/gh/wso2/identity-apps/pull/7929?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=wso2) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 41.85%. Comparing base [(`5b860f1`)](https://app.codecov.io/gh/wso2/identity-apps/commit/5b860f17d38841a3ef785b02a960258e36d70a7c?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=wso2) to head [(`cb0ee2c`)](https://app.codecov.io/gh/wso2/identity-apps/commit/cb0ee2cf165319ca096aa44d358799060f08bbf9?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=wso2).
> Report is 1097 commits behind head on master.

<details><summary>Additional details and impacted files</summary>


```diff
@@           Coverage Diff           @@
##           master    #7929   +/-   ##
=======================================
  Coverage   41.85%   41.85%           
=======================================
  Files          42       42           
  Lines         939      939           
  Branches      217      238   +21     
=======================================
  Hits          393      393           
+ Misses        546      502   -44     
- Partials        0       44   +44     
```

| [Flag](https://app.codecov.io/gh/wso2/identity-apps/pull/7929/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=wso2) | Coverage Δ | |
|---|---|---|
| [@wso2is/core](https://app.codecov.io/gh/wso2/identity-apps/pull/7929/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=wso2) | `41.85% <ø> (ø)` | |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=wso2#carryforward-flags-in-the-pull-request-comment) to find out more.

[see 12 files with indirect coverage changes](https://app.codecov.io/gh/wso2/identity-apps/pull/7929/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=wso2)

</details>
<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
- :package: [JS Bundle Analysis](https://docs.codecov.com/docs/javascript-bundle-analysis): Save yourself from yourself by tracking and limiting bundle sizes in JS merges.
</details>
author_association: NONE