Skip to content

Commit

Permalink
feat: add empty and leading states for Roles table (#1750)
Browse files Browse the repository at this point in the history
  • Loading branch information
apinkert authored Jan 29, 2025
1 parent e5b9aa8 commit c0d3ef4
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 7 deletions.
10 changes: 10 additions & 0 deletions src/Messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
72 changes: 65 additions & 7 deletions src/smart-components/role/RolesTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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 (
<EmptyState>
<EmptyStateHeader titleText={titleText} headingLevel="h4" icon={<EmptyStateIcon icon={SearchIcon} />} />
<EmptyStateBody>
<FormattedMessage
{...messages['rolesEmptyStateSubtitle']}
values={{
br: <br />,
}}
/>
</EmptyStateBody>
</EmptyState>
);
};

interface RoleFilters {
display_name: string;
Expand All @@ -35,9 +70,10 @@ interface RolesTableProps {
const RolesTable: React.FunctionComponent<RolesTableProps> = ({ selectedRole }) => {
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const [currentRoles, setCurrentRoles] = useState<Role[]>([]);
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();
Expand All @@ -60,6 +96,7 @@ const RolesTable: React.FunctionComponent<RolesTableProps> = ({ selectedRole })

const dispatch = useDispatch();
const [searchParams, setSearchParams] = useSearchParams();
const [activeState, setActiveState] = useState<DataViewState | undefined>(DataViewState.loading);
const { filters, onSetFilters, clearAllFilters } = useDataViewFilters<RoleFilters>({
initialFilters: { display_name: '' },
searchParams,
Expand Down Expand Up @@ -92,6 +129,14 @@ const RolesTable: React.FunctionComponent<RolesTableProps> = ({ selectedRole })
});
}, [fetchData, page, perPage, sortBy, direction]);

useEffect(() => {
if (isLoading) {
setActiveState(DataViewState.loading);
} else {
totalCount === 0 ? setActiveState(DataViewState.empty) : setActiveState(undefined);
}
}, [totalCount, isLoading]);

useEffect(() => {
debouncedFetch(
() =>
Expand Down Expand Up @@ -208,7 +253,7 @@ const RolesTable: React.FunctionComponent<RolesTableProps> = ({ selectedRole })
/>
</WarningModal>
)}
<DataView ouiaId={ouiaId} selection={selection}>
<DataView ouiaId={ouiaId} selection={selection} activeState={activeState}>
<DataViewToolbar
ouiaId={`${ouiaId}-header-toolbar`}
clearAllFilters={clearAllFilters}
Expand Down Expand Up @@ -259,7 +304,20 @@ const RolesTable: React.FunctionComponent<RolesTableProps> = ({ selectedRole })
/>
}
/>
<DataViewTable columns={columns} rows={rows} ouiaId={`${ouiaId}-table`} />
{isLoading ? (
<SkeletonTable rowsCount={10} columns={columns} variant={TableVariant.compact} />
) : (
<DataViewTable
columns={columns}
rows={rows}
ouiaId={`${ouiaId}-table`}
headStates={{ loading: <SkeletonTableHead columns={columns} /> }}
bodyStates={{
loading: <SkeletonTableBody rowsCount={10} columnsCount={columns.length} />,
empty: <EmptyTable titleText={intl.formatMessage(messages.rolesEmptyStateTitle)} />,
}}
/>
)}
<DataViewToolbar
ouiaId={`${ouiaId}-footer-toolbar`}
pagination={
Expand Down

0 comments on commit c0d3ef4

Please sign in to comment.