diff --git a/src/Messages.js b/src/Messages.js
index 79459ab93..76a3f0caf 100644
--- a/src/Messages.js
+++ b/src/Messages.js
@@ -2456,6 +2456,16 @@ export default defineMessages({
description: 'Empty state subtitle role bindings',
defaultMessage: 'This filter criteria matches no role assignments.{br}Try changing your filter input.',
},
+ rolesEmptyStateTitle: {
+ id: 'rolesEmptyStateTitle',
+ description: 'Empty state title Roles',
+ defaultMessage: 'No roles found',
+ },
+ rolesEmptyStateSubtitle: {
+ id: 'rolesEmptyStateSubtitle',
+ description: 'Empty state subtitle Roles',
+ defaultMessage: 'This filter criteria matches no roles.{br}Try changing your filter input.',
+ },
userGroupsEmptyStateTitle: {
id: 'userGroupsEmptyStateTitle',
description: 'Empty state title User groups',
diff --git a/src/smart-components/role/RolesTable.tsx b/src/smart-components/role/RolesTable.tsx
index c0d2faa30..39b106cbe 100644
--- a/src/smart-components/role/RolesTable.tsx
+++ b/src/smart-components/role/RolesTable.tsx
@@ -2,13 +2,24 @@ import React, { useEffect, useCallback, useState, useRef, useMemo } from 'react'
import { useSelector, useDispatch } from 'react-redux';
import { useDataViewSelection, useDataViewPagination } from '@patternfly/react-data-view/dist/dynamic/Hooks';
import { BulkSelect, BulkSelectValue } from '@patternfly/react-component-groups/dist/dynamic/BulkSelect';
-import { DataView } from '@patternfly/react-data-view/dist/dynamic/DataView';
+import { DataView, DataViewState } 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 { DataViewEventsProvider, EventTypes, useDataViewEventsContext } from '@patternfly/react-data-view/dist/dynamic/DataViewEventsContext';
import { useDataViewSort } from '@patternfly/react-data-view/dist/dynamic/Hooks';
-import { ButtonVariant, Drawer, DrawerContent, DrawerContentBody, PageSection, Pagination } from '@patternfly/react-core';
-import { ActionsColumn, ThProps } from '@patternfly/react-table';
+import {
+ ButtonVariant,
+ Drawer,
+ DrawerContent,
+ DrawerContentBody,
+ EmptyState,
+ EmptyStateBody,
+ EmptyStateHeader,
+ EmptyStateIcon,
+ PageSection,
+ Pagination,
+} from '@patternfly/react-core';
+import { ActionsColumn, TableVariant, ThProps } from '@patternfly/react-table';
import ContentHeader from '@patternfly/react-component-groups/dist/esm/ContentHeader';
import { fetchRolesWithPolicies, removeRole } from '../../redux/actions/role-actions';
import { FormattedMessage, useIntl } from 'react-intl';
@@ -18,9 +29,33 @@ import { Role } from '../../redux/reducers/role-reducer';
import { RBACStore } from '../../redux/store';
import { useSearchParams } from 'react-router-dom';
import RolesDetails from './RolesTableDetails';
-import { ResponsiveAction, ResponsiveActions, WarningModal } from '@patternfly/react-component-groups';
+import {
+ ResponsiveAction,
+ ResponsiveActions,
+ SkeletonTable,
+ SkeletonTableBody,
+ SkeletonTableHead,
+ WarningModal,
+} from '@patternfly/react-component-groups';
import { DataViewTextFilter, DataViewTh, DataViewTr, DataViewTrObject, useDataViewFilters } from '@patternfly/react-data-view';
import { PER_PAGE_OPTIONS } from '../../helpers/shared/pagination';
+import { SearchIcon } from '@patternfly/react-icons';
+
+const EmptyTable: React.FunctionComponent<{ titleText: string }> = ({ titleText }) => {
+ return (
+
+ } />
+
+ ,
+ }}
+ />
+
+
+ );
+};
interface RoleFilters {
display_name: string;
@@ -35,9 +70,10 @@ interface RolesTableProps {
const RolesTable: React.FunctionComponent = ({ selectedRole }) => {
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const [currentRoles, setCurrentRoles] = useState([]);
- const { roles, totalCount } = useSelector((state: RBACStore) => ({
+ const { roles, totalCount, isLoading } = useSelector((state: RBACStore) => ({
roles: state.roleReducer.roles.data || [],
totalCount: state.roleReducer.roles.meta.count,
+ isLoading: state.roleReducer.isLoading,
}));
const { trigger } = useDataViewEventsContext();
@@ -60,6 +96,7 @@ const RolesTable: React.FunctionComponent = ({ selectedRole })
const dispatch = useDispatch();
const [searchParams, setSearchParams] = useSearchParams();
+ const [activeState, setActiveState] = useState(DataViewState.loading);
const { filters, onSetFilters, clearAllFilters } = useDataViewFilters({
initialFilters: { display_name: '' },
searchParams,
@@ -92,6 +129,14 @@ const RolesTable: React.FunctionComponent = ({ selectedRole })
});
}, [fetchData, page, perPage, sortBy, direction]);
+ useEffect(() => {
+ if (isLoading) {
+ setActiveState(DataViewState.loading);
+ } else {
+ totalCount === 0 ? setActiveState(DataViewState.empty) : setActiveState(undefined);
+ }
+ }, [totalCount, isLoading]);
+
useEffect(() => {
debouncedFetch(
() =>
@@ -208,7 +253,7 @@ const RolesTable: React.FunctionComponent = ({ selectedRole })
/>
)}
-
+
= ({ selectedRole })
/>
}
/>
-
+ {isLoading ? (
+
+ ) : (
+ }}
+ bodyStates={{
+ loading: ,
+ empty: ,
+ }}
+ />
+ )}