Skip to content

Commit

Permalink
feat(WS): add loading and empty state to workspace list table (#1751)
Browse files Browse the repository at this point in the history
* feat: add loading and empty state to workspace list table

* fix: remove extra isLoading as it is not needed

* fix: update src/smart-components/workspaces/WorkspaceListTable.tsx

Co-authored-by: Karel Hala <[email protected]>

* fix(DW): Update src/smart-components/workspaces/WorkspaceListTable.tsx

* fix(lint): update src/smart-components/workspaces/WorkspaceListTable.tsx

---------

Co-authored-by: Karel Hala <[email protected]>
  • Loading branch information
aferd and karelhala authored Jan 31, 2025
1 parent f3714e3 commit b2e8f1d
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 8 deletions.
10 changes: 10 additions & 0 deletions src/Messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -1195,6 +1195,16 @@ export default defineMessages({
description: 'Create newworkspace action label',
defaultMessage: 'Workspace description',
},
workspaceEmptyStateTitle: {
id: 'workspaceEmptyStateTitle',
description: 'Empty State Title Workspaces',
defaultMessage: 'No workspaces found',
},
workspaceEmptyStateSubtitle: {
id: 'workspaceEmptyStateSubtitle',
description: 'Empty State Subtitle Workspaces',
defaultMessage: 'This filter criteria matches no workspaces.{br}Try changing your filter input.',
},
setEarmark: {
id: 'setEarmark',
description: 'Set ear mark step label',
Expand Down
60 changes: 52 additions & 8 deletions src/smart-components/workspaces/WorkspaceListTable.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
import React, { Suspense, useEffect, useMemo } from 'react';
import React, { Suspense, useEffect, useMemo, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { Outlet, useSearchParams } from 'react-router-dom';
import { useIntl } from 'react-intl';
import { FormattedMessage, useIntl } from 'react-intl';
import { fetchWorkspaces } from '../../redux/actions/workspaces-actions';
import { BulkSelect, BulkSelectValue, ErrorState, ResponsiveAction, ResponsiveActions, SkeletonTableBody } from '@patternfly/react-component-groups';
import {
BulkSelect,
BulkSelectValue,
ErrorState,
ResponsiveAction,
ResponsiveActions,
SkeletonTableBody,
SkeletonTableHead,
} from '@patternfly/react-component-groups';
import {
DataView,
DataViewTable,
DataViewState,
DataViewTextFilter,
useDataViewFilters,
DataViewTable,
DataViewTh,
DataViewToolbar,
DataViewTrTree,
useDataViewFilters,
useDataViewSelection,
} from '@patternfly/react-data-view';
import { Workspace } from '../../redux/reducers/workspaces-reducer';
Expand All @@ -20,6 +29,8 @@ import AppLink from '../../presentational-components/shared/AppLink';
import pathnames from '../../utilities/pathnames';
import messages from '../../Messages';
import useAppNavigate from '../../hooks/useAppNavigate';
import { EmptyState, EmptyStateHeader, EmptyStateIcon, EmptyStateBody } from '@patternfly/react-core';
import { SearchIcon } from '@patternfly/react-icons';

interface WorkspaceFilters {
name: string;
Expand Down Expand Up @@ -59,6 +70,21 @@ const buildRows = (workspaces: Workspace[]): DataViewTrTree[] =>
: {}),
}));

const EmptyWorkspacesTable: React.FunctionComponent<{ titleText: string }> = ({ titleText }) => {
return (
<EmptyState>
<EmptyStateHeader titleText={titleText} headingLevel="h4" icon={<EmptyStateIcon icon={SearchIcon} />} />
<EmptyStateBody>
<FormattedMessage
{...messages['workspaceEmptyStateSubtitle']}
values={{
br: <br />,
}}
/>
</EmptyStateBody>
</EmptyState>
);
};
const search = (workspaceTree: Workspace[], filter: string): Workspace[] => {
const matches: Workspace[] = [];
if (!Array.isArray(workspaceTree)) {
Expand Down Expand Up @@ -91,7 +117,13 @@ const WorkspaceListTable = () => {
const navigate = useAppNavigate();
const selection = useDataViewSelection({ matchOption: (a, b) => a.id === b.id });

const { isLoading, workspaces, error } = useSelector((state: RBACStore) => state.workspacesReducer);
const { isLoading, workspaces, error } = useSelector((state: RBACStore) => ({
workspaces: state.workspacesReducer.workspaces || [],
error: state.workspacesReducer.error,
isLoading: state.workspacesReducer.isLoading,
}));

const [activeState, setActiveState] = useState<DataViewState | undefined>(DataViewState.loading);
const [searchParams, setSearchParams] = useSearchParams();
const { filters, onSetFilters, clearAllFilters } = useDataViewFilters<WorkspaceFilters>({
initialFilters: { name: '' },
Expand All @@ -104,6 +136,14 @@ const WorkspaceListTable = () => {
const rows = useMemo(() => (filteredTree ? buildRows(filteredTree) : []), [filteredTree]);
const columns: DataViewTh[] = [intl.formatMessage(messages.name), intl.formatMessage(messages.description)];

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

useEffect(() => {
dispatch(fetchWorkspaces());
}, [dispatch]);
Expand All @@ -118,7 +158,7 @@ const WorkspaceListTable = () => {

return (
<React.Fragment>
<DataView selection={selection} activeState={isLoading ? 'loading' : undefined}>
<DataView selection={selection} activeState={activeState}>
<DataViewToolbar
bulkSelect={
<BulkSelect
Expand Down Expand Up @@ -156,7 +196,11 @@ const WorkspaceListTable = () => {
ouiaId="workspaces-list"
columns={columns}
rows={rows}
bodyStates={{ loading: <SkeletonTableBody rowsCount={10} columnsCount={2} /> }}
headStates={{ loading: <SkeletonTableHead columns={columns} /> }}
bodyStates={{
loading: <SkeletonTableBody rowsCount={10} columnsCount={columns.length} />,
empty: <EmptyWorkspacesTable titleText={intl.formatMessage(messages.workspaceEmptyStateTitle)} />,
}}
/>
</DataView>
<Suspense>
Expand Down

0 comments on commit b2e8f1d

Please sign in to comment.