= ({
+ defaultPerPage = 20,
+ useUrlParams = true,
+ enableActions = true,
+ ouiaId = 'iam-user-groups-table',
+ onChange,
+}) => {
const dispatch = useDispatch();
+ const intl = useIntl();
+
+ const rowActions = [
+ { title: intl.formatMessage(messages['usersAndUserGroupsEditUserGroup']), onClick: () => console.log('EDIT USER GROUP') },
+ { title: intl.formatMessage(messages['usersAndUserGroupsDeleteUserGroup']), onClick: () => console.log('DELETE USER GROUP') },
+ ];
const { groups, totalCount } = useSelector((state: RBACStore) => ({
groups: state.groupReducer?.groups?.data || [],
totalCount: state.groupReducer?.groups?.meta.count || 0,
}));
- const [searchParams, setSearchParams] = useSearchParams();
- const pagination = useDataViewPagination({ perPage: 20, searchParams, setSearchParams });
+ let pagination;
+
+ if (useUrlParams) {
+ const [searchParams, setSearchParams] = useSearchParams();
+ pagination = useDataViewPagination({
+ perPage: defaultPerPage,
+ searchParams: searchParams,
+ setSearchParams: setSearchParams,
+ });
+ } else {
+ const [perPage, setPerPage] = React.useState(defaultPerPage);
+ const [page, setPage] = React.useState(1);
+ pagination = {
+ page,
+ perPage,
+ onSetPage: (_e: any, page: number) => setPage(page),
+ onPerPageSelect: (_e: any, perPage: number) => setPerPage(perPage),
+ };
+ }
const { page, perPage, onSetPage, onPerPageSelect } = pagination;
- const selection = useDataViewSelection({ matchOption: (a, b) => a[0] === b[0] });
+ const selection = useDataViewSelection({ matchOption: (a, b) => a.id === b.id });
const { selected, onSelect, isSelected } = selection;
const fetchData = useCallback(
(apiProps: { count: number; limit: number; offset: number; orderBy: string }) => {
const { count, limit, offset, orderBy } = apiProps;
- dispatch(fetchGroups({ ...mappedProps({ count, limit, offset, orderBy }), usesMetaInURL: true }));
+ dispatch(fetchGroups({ ...mappedProps({ count, limit, offset, orderBy }), usesMetaInURL: true, system: false }));
},
[dispatch]
);
@@ -62,6 +94,10 @@ const UserGroupsTable: React.FunctionComponent = () => {
});
}, [fetchData, page, perPage]);
+ useEffect(() => {
+ onChange?.(selected);
+ }, [selected]);
+
const handleBulkSelect = (value: BulkSelectValue) => {
if (value === BulkSelectValue.none) {
onSelect(false);
@@ -72,25 +108,28 @@ const UserGroupsTable: React.FunctionComponent = () => {
}
};
- const rows = groups.map((group: any) => [
- group.name,
- group.description ? (
-
- {group.description.length > 23 ? group.description.slice(0, 20) + '...' : group.description}
-
- ) : (
- No description
- ),
- group.principalCount,
- group.serviceAccounts || '?', // not currently in API
- group.roleCount,
- group.workspaces || '?', // not currently in API
- formatDistanceToNow(new Date(group.modified), { addSuffix: true }),
- {
- cell: ,
- props: { isActionCell: true },
- },
- ]);
+ const rows = groups.map((group: any) => ({
+ id: group.uuid,
+ row: [
+ group.name,
+ group.description ? (
+
+ {group.description.length > 23 ? group.description.slice(0, 20) + '...' : group.description}
+
+ ) : (
+ {intl.formatMessage(messages['usersAndUserGroupsNoDescription'])}
+ ),
+ group.principalCount,
+ group.serviceAccounts || '?', // not currently in API
+ group.roleCount,
+ group.workspaces || '?', // not currently in API
+ formatDistanceToNow(new Date(group.modified), { addSuffix: true }),
+ enableActions && {
+ cell: ,
+ props: { isActionCell: true },
+ },
+ ],
+ }));
const pageSelected = rows.length > 0 && rows.every(isSelected);
const pagePartiallySelected = !pageSelected && rows.some(isSelected);
@@ -107,9 +146,9 @@ const UserGroupsTable: React.FunctionComponent = () => {
);
return (
-
+
{
}
pagination={React.cloneElement(paginationComponent, { isCompact: true })}
/>
-
-
+
+
);
};
diff --git a/src/smart-components/access-management/UsersTable.tsx b/src/smart-components/access-management/UsersTable.tsx
index 51de4cf1a..413ed74eb 100644
--- a/src/smart-components/access-management/UsersTable.tsx
+++ b/src/smart-components/access-management/UsersTable.tsx
@@ -5,7 +5,7 @@ import { BulkSelect, BulkSelectValue } from '@patternfly/react-component-groups/
import { DataView } from '@patternfly/react-data-view/dist/dynamic/DataView';
import { DataViewToolbar } from '@patternfly/react-data-view/dist/dynamic/DataViewToolbar';
import { DataViewTable } from '@patternfly/react-data-view/dist/dynamic/DataViewTable';
-import { ButtonVariant, Pagination } from '@patternfly/react-core';
+import { Button, Pagination, ButtonVariant } from '@patternfly/react-core';
import { ActionsColumn } from '@patternfly/react-table';
import { fetchUsers } from '../../redux/actions/user-actions';
import { mappedProps } from '../../helpers/shared/helpers';
@@ -15,6 +15,7 @@ import { useIntl } from 'react-intl';
import messages from '../../Messages';
import { useSearchParams } from 'react-router-dom';
import { WarningModal } from '@patternfly/react-component-groups';
+import { UserProps } from '../user/user-table-helpers';
const COLUMNS: string[] = ['Username', 'Email', 'First name', 'Last name', 'Status', 'Org admin'];
@@ -28,11 +29,14 @@ const PER_PAGE_OPTIONS = [
const OUIA_ID = 'iam-users-table';
-const UsersTable: React.FunctionComponent = () => {
+interface UsersTableProps {
+ onAddUserClick: (selected: any[]) => void;
+}
+
+const UsersTable: React.FunctionComponent = ({ onAddUserClick }) => {
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const [currentUser, setCurrentUser] = useState();
const dispatch = useDispatch();
-
const intl = useIntl();
const handleModalToggle = (_event: KeyboardEvent | React.MouseEvent, user: User) => {
@@ -49,7 +53,7 @@ const UsersTable: React.FunctionComponent = () => {
const pagination = useDataViewPagination({ perPage: 20, searchParams, setSearchParams });
const { page, perPage, onSetPage, onPerPageSelect } = pagination;
- const selection = useDataViewSelection({ matchOption: (a, b) => a[0] === b[0] });
+ const selection = useDataViewSelection({ matchOption: (a, b) => a.id === b.id });
const { selected, onSelect, isSelected } = selection;
const fetchData = useCallback(
@@ -80,30 +84,37 @@ const UsersTable: React.FunctionComponent = () => {
};
const rows = useMemo(() => {
- return users.map((user: User) => [
- user.username,
- user.email,
- user.first_name,
- user.last_name,
- user.is_active ? 'Active' : 'Inactive',
- user.is_org_admin ? 'Yes' : 'No',
- {
- cell: (
- console.log('ADD TO USER GROUP') },
- {
- title: intl.formatMessage(messages.removeFromUserGroup),
- onClick: (event: KeyboardEvent | React.MouseEvent, rowId: number, rowData: any) => handleModalToggle(event, rowData),
- },
- ]}
- rowData={user}
- />
- ),
- props: { isActionCell: true },
- },
- ]);
- }, [users]);
+ return users.map((user: UserProps) => ({
+ id: user.username,
+ is_active: user.is_active,
+ row: [
+ user.username,
+ user.email,
+ user.first_name,
+ user.last_name,
+ user.is_active ? intl.formatMessage(messages['usersAndUserGroupsActive']) : intl.formatMessage(messages['usersAndUserGroupsInactive']),
+ user.is_org_admin ? intl.formatMessage(messages['usersAndUserGroupsYes']) : intl.formatMessage(messages['usersAndUserGroupsNo']),
+ {
+ cell: (
+ onAddUserClick([user]),
+ },
+ {
+ title: intl.formatMessage(messages['usersAndUserGroupsRemoveFromGroup']),
+ onClick: (event: KeyboardEvent | React.MouseEvent, rowId: number, rowData: any) => handleModalToggle(event, rowData),
+ },
+ ]}
+ rowData={user}
+ />
+ ),
+ props: { isActionCell: true },
+ },
+ ],
+ }));
+ }, [users, intl, onAddUserClick, handleModalToggle]);
const pageSelected = rows.length > 0 && rows.every(isSelected);
const pagePartiallySelected = !pageSelected && rows.some(isSelected);
@@ -138,7 +149,7 @@ const UsersTable: React.FunctionComponent = () => {
{`${currentUser?.username} ${intl.formatMessage(messages.deleteUserModalBody)}`}
)}
-
+ !row.is_active }}>
{
/>
}
pagination={React.cloneElement(paginationComponent, { isCompact: true })}
+ actions={
+
+ }
/>
diff --git a/src/smart-components/access-management/users-and-user-groups.tsx b/src/smart-components/access-management/users-and-user-groups.tsx
index fb22cfbb5..663cd978c 100644
--- a/src/smart-components/access-management/users-and-user-groups.tsx
+++ b/src/smart-components/access-management/users-and-user-groups.tsx
@@ -6,12 +6,15 @@ import Messages from '../../Messages';
import UsersTable from './UsersTable';
import UserGroupsTable from './UserGroupsTable';
import { useLocation, useNavigate } from 'react-router-dom';
+import AddUserGroupModal from './AddUserGroupModal';
const TAB_NAMES = ['users', 'user-groups'];
const UsersAndUserGroups: React.FunctionComponent = () => {
const intl = useIntl();
const [activeTabKey, setActiveTabKey] = React.useState(0);
+ const [isAddUserGroupModalOpen, setIsAddUserGroupModalOpen] = React.useState(false);
+ const [selectedUsers, setSelectedUsers] = React.useState([]);
const usersRef = React.createRef();
const groupsRef = React.createRef();
@@ -31,6 +34,13 @@ const UsersAndUserGroups: React.FunctionComponent = () => {
updateURL(TAB_NAMES[activeTab]);
};
+ const handleOpenAddUserModal = (selected: any[]) => {
+ if (selected.length > 0) {
+ setSelectedUsers(selected);
+ setIsAddUserGroupModalOpen(true);
+ }
+ };
+
useEffect(() => {
const params = new URLSearchParams(location.search);
const tabKey = params.get('activeTab');
@@ -39,6 +49,7 @@ const UsersAndUserGroups: React.FunctionComponent = () => {
return (
+
{
-
-
-
-
-
-
+ {activeTabKey === 0 && (
+
+
+
+ )}
+ {activeTabKey === 1 && (
+
+
+
+ )}
);