diff --git a/package-lock.json b/package-lock.json
index 23115dc80..f8ac998be 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -59,7 +59,7 @@
"@commitlint/cli": "^19.5.0",
"@commitlint/config-conventional": "^19.5.0",
"@redhat-cloud-services/eslint-config-redhat-cloud-services": "^2.0.3",
- "@redhat-cloud-services/frontend-components-config": "^6.3.1",
+ "@redhat-cloud-services/frontend-components-config": "^6.3.3",
"@redhat-cloud-services/tsc-transform-imports": "^1.0.4",
"@semantic-release/changelog": "^6.0.3",
"@semantic-release/commit-analyzer": "^13.0.0",
@@ -3935,7 +3935,8 @@
},
"node_modules/@openshift/dynamic-plugin-sdk": {
"version": "5.0.1",
- "license": "Apache-2.0",
+ "resolved": "https://registry.npmjs.org/@openshift/dynamic-plugin-sdk/-/dynamic-plugin-sdk-5.0.1.tgz",
+ "integrity": "sha512-+azUBN6FgcDmlcWMzG0bthcRUJC1u12wf9xa2aJGFbC/uTiOXwjrkcQ7LW/PyK5Em7wDhwaUdapaeOgh8I6Kjg==",
"dependencies": {
"lodash": "^4.17.21",
"semver": "^7.3.7",
@@ -3975,22 +3976,10 @@
"node": ">=10"
}
},
- "node_modules/@openshift/dynamic-plugin-sdk/node_modules/lru-cache": {
- "version": "6.0.0",
- "license": "ISC",
- "dependencies": {
- "yallist": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
"node_modules/@openshift/dynamic-plugin-sdk/node_modules/semver": {
- "version": "7.5.4",
- "license": "ISC",
- "dependencies": {
- "lru-cache": "^6.0.0"
- },
+ "version": "7.6.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
+ "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
"bin": {
"semver": "bin/semver.js"
},
@@ -3998,10 +3987,6 @@
"node": ">=10"
}
},
- "node_modules/@openshift/dynamic-plugin-sdk/node_modules/yallist": {
- "version": "4.0.0",
- "license": "ISC"
- },
"node_modules/@patternfly/quickstarts": {
"version": "5.1.0",
"license": "MIT",
@@ -4621,16 +4606,17 @@
}
},
"node_modules/@redhat-cloud-services/frontend-components": {
- "version": "4.2.13",
- "license": "Apache-2.0",
+ "version": "4.2.22",
+ "resolved": "https://registry.npmjs.org/@redhat-cloud-services/frontend-components/-/frontend-components-4.2.22.tgz",
+ "integrity": "sha512-FEDxxNHF0Jg6thM1IIFxHZSVbsS5Eq4QxOuPvbhlXA7ijvxzkgh5hDwBZyRSYhL2za+sZPqZzYTgwwu1Mb3MNw==",
"dependencies": {
"@patternfly/react-component-groups": "^5.0.0",
"@redhat-cloud-services/frontend-components-utilities": "^4.0.0",
"@redhat-cloud-services/types": "^1.0.9",
- "@scalprum/core": "^0.7.0",
- "@scalprum/react-core": "^0.8.0",
+ "@scalprum/core": "^0.8.1",
+ "@scalprum/react-core": "^0.9.1",
"classnames": "^2.2.5",
- "sanitize-html": "^2.12.1"
+ "sanitize-html": "^2.13.1"
},
"peerDependencies": {
"@patternfly/react-core": "^5.0.0",
@@ -4646,9 +4632,9 @@
}
},
"node_modules/@redhat-cloud-services/frontend-components-config": {
- "version": "6.3.1",
- "resolved": "https://registry.npmjs.org/@redhat-cloud-services/frontend-components-config/-/frontend-components-config-6.3.1.tgz",
- "integrity": "sha512-WLItTdGoIrc0s7QsrjGpcxELQljHSZXrPCTyf9y9fv1QopOtQRoWSIAMolDzABquWQ98HPeMyz4XsJRF7PCX1Q==",
+ "version": "6.3.3",
+ "resolved": "https://registry.npmjs.org/@redhat-cloud-services/frontend-components-config/-/frontend-components-config-6.3.3.tgz",
+ "integrity": "sha512-+vprQN6SYW8gTbv9mdwbFzfZbBziVhdpUpDstDq2rBv42Qb96WEY1titfVypCZC4iGsbRu6uYJfnWYKvpZXekQ==",
"dev": true,
"dependencies": {
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.15",
@@ -5298,20 +5284,21 @@
}
},
"node_modules/@scalprum/core": {
- "version": "0.7.0",
- "license": "Apache-2.0",
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/@scalprum/core/-/core-0.8.1.tgz",
+ "integrity": "sha512-bRbquESsjUvgu3QHA9aDIK5uTu7XoXjzqoxAmDmytnedzg8LFk/iNKs/bx4lSP2rufxx8iFkdVVvN3sM1W6a4A==",
"dependencies": {
"@openshift/dynamic-plugin-sdk": "^5.0.1",
"tslib": "^2.6.2"
}
},
"node_modules/@scalprum/react-core": {
- "version": "0.8.0",
- "resolved": "https://registry.npmjs.org/@scalprum/react-core/-/react-core-0.8.0.tgz",
- "integrity": "sha512-ADqL6GdjT0ihVfTtIqu8vvYgwUb3IiUGXj9md1+h6tL8yshbq+FAezwuD9jhX7qcjfgL1Sl3g/faO2/SE9jPvw==",
+ "version": "0.9.3",
+ "resolved": "https://registry.npmjs.org/@scalprum/react-core/-/react-core-0.9.3.tgz",
+ "integrity": "sha512-AnBoFLZl+qYB9XnAJBHYZJTHHRFWCW6iYAojGkiqtD4luyiEMmd6SaCv2s8xs/b6l/KKkG2FU272sIYqb/FkAQ==",
"dependencies": {
"@openshift/dynamic-plugin-sdk": "^5.0.1",
- "@scalprum/core": "^0.7.0",
+ "@scalprum/core": "^0.8.1",
"lodash": "^4.17.0"
},
"peerDependencies": {
@@ -21622,7 +21609,8 @@
},
"node_modules/parse-srcset": {
"version": "1.0.2",
- "license": "MIT"
+ "resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz",
+ "integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q=="
},
"node_modules/parse5": {
"version": "7.1.2",
@@ -23273,8 +23261,9 @@
"license": "MIT"
},
"node_modules/sanitize-html": {
- "version": "2.13.0",
- "license": "MIT",
+ "version": "2.13.1",
+ "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.13.1.tgz",
+ "integrity": "sha512-ZXtKq89oue4RP7abL9wp/9URJcqQNABB5GGJ2acW1sdO8JTVl92f4ygD7Yc9Ze09VAZhnt2zegeU0tbNsdcLYg==",
"dependencies": {
"deepmerge": "^4.2.2",
"escape-string-regexp": "^4.0.0",
@@ -23286,7 +23275,8 @@
},
"node_modules/sanitize-html/node_modules/dom-serializer": {
"version": "2.0.0",
- "license": "MIT",
+ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
+ "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
"dependencies": {
"domelementtype": "^2.3.0",
"domhandler": "^5.0.2",
@@ -23298,7 +23288,8 @@
},
"node_modules/sanitize-html/node_modules/domhandler": {
"version": "5.0.3",
- "license": "BSD-2-Clause",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
+ "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
"dependencies": {
"domelementtype": "^2.3.0"
},
@@ -23311,7 +23302,8 @@
},
"node_modules/sanitize-html/node_modules/domutils": {
"version": "3.1.0",
- "license": "BSD-2-Clause",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz",
+ "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==",
"dependencies": {
"dom-serializer": "^2.0.0",
"domelementtype": "^2.3.0",
@@ -23323,7 +23315,8 @@
},
"node_modules/sanitize-html/node_modules/escape-string-regexp": {
"version": "4.0.0",
- "license": "MIT",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
"engines": {
"node": ">=10"
},
@@ -23333,6 +23326,8 @@
},
"node_modules/sanitize-html/node_modules/htmlparser2": {
"version": "8.0.2",
+ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz",
+ "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==",
"funding": [
"https://github.com/fb55/htmlparser2?sponsor=1",
{
@@ -23340,7 +23335,6 @@
"url": "https://github.com/sponsors/fb55"
}
],
- "license": "MIT",
"dependencies": {
"domelementtype": "^2.3.0",
"domhandler": "^5.0.3",
diff --git a/package.json b/package.json
index 0432e5f77..9ec5f491e 100644
--- a/package.json
+++ b/package.json
@@ -87,7 +87,7 @@
"@commitlint/cli": "^19.5.0",
"@commitlint/config-conventional": "^19.5.0",
"@redhat-cloud-services/eslint-config-redhat-cloud-services": "^2.0.3",
- "@redhat-cloud-services/frontend-components-config": "^6.3.1",
+ "@redhat-cloud-services/frontend-components-config": "^6.3.3",
"@redhat-cloud-services/tsc-transform-imports": "^1.0.4",
"@semantic-release/changelog": "^6.0.3",
"@semantic-release/commit-analyzer": "^13.0.0",
diff --git a/src/Messages.js b/src/Messages.js
index a3073446c..dec27ac25 100644
--- a/src/Messages.js
+++ b/src/Messages.js
@@ -2294,6 +2294,26 @@ export default defineMessages({
defaultMessage:
'Select a user group to add {numUsers} {plural} to. These are all the user groups in your account. To manage user groups, go to user groups.',
},
+ usersEmptyStateTitle: {
+ id: 'usersEmptyStateTitle',
+ description: 'Empty state title Users',
+ defaultMessage: 'No users found',
+ },
+ usersEmptyStateSubtitle: {
+ id: 'usersEmptyStateSubtitle',
+ description: 'Empty state subtitle Users',
+ defaultMessage: 'This filter criteria matches no users.{br}Try changing your filter input.',
+ },
+ userGroupsEmptyStateTitle: {
+ id: 'userGroupsEmptyStateTitle',
+ description: 'Empty state title User groups',
+ defaultMessage: 'No user group found',
+ },
+ userGroupsEmptyStateSubtitle: {
+ id: 'userGroupsEmptyStateSubtitle',
+ description: 'Empty state subtitle User groups',
+ defaultMessage: 'This filter criteria matches no user groups.{br}Try changing your filter input.',
+ },
assignedRoles: {
id: 'assignedRoles',
description: 'User details assigned roles label',
diff --git a/src/smart-components/access-management/UserGroupsTable.tsx b/src/smart-components/access-management/UserGroupsTable.tsx
index ede9ebf5d..a4a8651c8 100644
--- a/src/smart-components/access-management/UserGroupsTable.tsx
+++ b/src/smart-components/access-management/UserGroupsTable.tsx
@@ -1,21 +1,23 @@
-import React, { useEffect, useCallback, useMemo } from 'react';
+import React, { useEffect, useCallback, useMemo, useState } 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 { DataViewToolbar } from '@patternfly/react-data-view/dist/dynamic/DataViewToolbar';
import { DataViewTable } from '@patternfly/react-data-view/dist/dynamic/DataViewTable';
-import { Pagination, Tooltip } from '@patternfly/react-core';
-import { ActionsColumn } from '@patternfly/react-table';
+import { EmptyState, EmptyStateBody, EmptyStateHeader, EmptyStateIcon, Pagination, Tooltip } from '@patternfly/react-core';
+import { ActionsColumn, TableVariant } from '@patternfly/react-table';
import { mappedProps } from '../../helpers/shared/helpers';
import { RBACStore } from '../../redux/store';
import { useSearchParams } from 'react-router-dom';
import { fetchGroups } from '../../redux/actions/group-actions';
import { formatDistanceToNow } from 'date-fns';
-import { useIntl } from 'react-intl';
+import { FormattedMessage, useIntl } from 'react-intl';
import messages from '../../Messages';
import { Group } from '../../redux/reducers/group-reducer';
-import { EventTypes, useDataViewEventsContext } from '@patternfly/react-data-view';
+import { DataViewState, EventTypes, useDataViewEventsContext } from '@patternfly/react-data-view';
+import { SearchIcon } from '@patternfly/react-icons';
+import { SkeletonTable } from '@patternfly/react-component-groups';
const COLUMNS: string[] = ['User group name', 'Description', 'Users', 'Service accounts', 'Roles', 'Workspaces', 'Last modified'];
@@ -45,6 +47,7 @@ const UserGroupsTable: React.FunctionComponent = ({
focusedGroup,
}) => {
const dispatch = useDispatch();
+ const [activeState, setActiveState] = useState(DataViewState.loading);
const intl = useIntl();
const { trigger } = useDataViewEventsContext();
@@ -53,9 +56,10 @@ const UserGroupsTable: React.FunctionComponent = ({
{ title: intl.formatMessage(messages['usersAndUserGroupsDeleteUserGroup']), onClick: () => console.log('DELETE USER GROUP') },
];
- const { groups, totalCount } = useSelector((state: RBACStore) => ({
+ const { groups, totalCount, isLoading } = useSelector((state: RBACStore) => ({
groups: state.groupReducer?.groups?.data || [],
totalCount: state.groupReducer?.groups?.meta.count || 0,
+ isLoading: state.groupReducer?.isLoading,
}));
let pagination;
@@ -99,6 +103,14 @@ const UserGroupsTable: React.FunctionComponent = ({
});
}, [fetchData, page, perPage]);
+ useEffect(() => {
+ if (isLoading) {
+ setActiveState(DataViewState.loading);
+ } else {
+ totalCount === 0 ? setActiveState(DataViewState.empty) : setActiveState(undefined);
+ }
+ }, [totalCount, isLoading]);
+
useEffect(() => {
onChange?.(selected);
}, [selected]);
@@ -161,8 +173,26 @@ const UserGroupsTable: React.FunctionComponent = ({
/>
);
+ const empty = (
+
+ }
+ />
+
+ ,
+ }}
+ />
+
+
+ );
+
return (
-
+
= ({
}
pagination={React.cloneElement(paginationComponent, { isCompact: true })}
/>
-
+ {isLoading ? (
+
+ ) : (
+
+ )}
);
diff --git a/src/smart-components/access-management/UsersTable.tsx b/src/smart-components/access-management/UsersTable.tsx
index 9bb29e406..f01b288b3 100644
--- a/src/smart-components/access-management/UsersTable.tsx
+++ b/src/smart-components/access-management/UsersTable.tsx
@@ -7,20 +7,21 @@ import { ResponsiveActions } from '@patternfly/react-component-groups/dist/dynam
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 { Pagination, ButtonVariant } from '@patternfly/react-core';
-import { ActionsColumn } from '@patternfly/react-table';
+import { ButtonVariant, Pagination, EmptyState, EmptyStateHeader, EmptyStateIcon, EmptyStateBody } from '@patternfly/react-core';
+import { ActionsColumn, TableVariant } from '@patternfly/react-table';
import { fetchUsers } from '../../redux/actions/user-actions';
import { mappedProps } from '../../helpers/shared/helpers';
import { RBACStore } from '../../redux/store';
import { User } from '../../redux/reducers/user-reducer';
-import { useIntl } from 'react-intl';
+import { FormattedMessage, useIntl } from 'react-intl';
import messages from '../../Messages';
import { Outlet, useSearchParams } from 'react-router-dom';
-import { WarningModal } from '@patternfly/react-component-groups';
-import { EventTypes, useDataViewEventsContext } from '@patternfly/react-data-view';
+import { SkeletonTable, WarningModal } from '@patternfly/react-component-groups';
import paths from '../../utilities/pathnames';
import useChrome from '@redhat-cloud-services/frontend-components/useChrome';
import useAppNavigate from '../../hooks/useAppNavigate';
+import { DataViewState, EventTypes, useDataViewEventsContext } from '@patternfly/react-data-view';
+import { SearchIcon } from '@patternfly/react-icons';
const COLUMNS: string[] = ['Username', 'Email', 'First name', 'Last name', 'Status', 'Org admin'];
@@ -42,6 +43,7 @@ interface UsersTableProps {
const UsersTable: React.FunctionComponent = ({ onAddUserClick, focusedUser }) => {
const { getBundle, getApp } = useChrome();
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
+ const [activeState, setActiveState] = useState(DataViewState.loading);
const [currentUser, setCurrentUser] = useState();
const dispatch = useDispatch();
const intl = useIntl();
@@ -53,9 +55,10 @@ const UsersTable: React.FunctionComponent = ({ onAddUserClick,
setIsDeleteModalOpen(!isDeleteModalOpen);
};
- const { users, totalCount } = useSelector((state: RBACStore) => ({
+ const { users, totalCount, isLoading } = useSelector((state: RBACStore) => ({
users: state.userReducer.users.data || [],
totalCount: state.userReducer.users.meta.count,
+ isLoading: state.userReducer.isUserDataLoading,
}));
const [searchParams, setSearchParams] = useSearchParams();
@@ -82,6 +85,14 @@ const UsersTable: React.FunctionComponent = ({ onAddUserClick,
});
}, [fetchData, page, perPage]);
+ useEffect(() => {
+ if (isLoading) {
+ setActiveState(DataViewState.loading);
+ } else {
+ totalCount === 0 ? setActiveState(DataViewState.empty) : setActiveState(undefined);
+ }
+ }, [totalCount, isLoading]);
+
const handleBulkSelect = (value: BulkSelectValue) => {
if (value === BulkSelectValue.none) {
onSelect(false);
@@ -148,6 +159,20 @@ const UsersTable: React.FunctionComponent = ({ onAddUserClick,
/>
);
+ const empty = (
+
+ } />
+
+ ,
+ }}
+ />
+
+
+ );
+
return (
{isDeleteModalOpen && (
@@ -167,7 +192,7 @@ const UsersTable: React.FunctionComponent = ({ onAddUserClick,
{`${currentUser?.username} ${intl.formatMessage(messages.deleteUserModalBody)}`}
)}
- !row.is_active }}>
+ !row.is_active }} activeState={activeState}>
= ({ onAddUserClick,
}
/>
-
+ {isLoading ? (
+
+ ) : (
+
+ )}
diff --git a/src/test/role/__snapshots__/role.test.js.snap b/src/test/role/__snapshots__/role.test.js.snap
index 9ac1c3b80..a798825c0 100644
--- a/src/test/role/__snapshots__/role.test.js.snap
+++ b/src/test/role/__snapshots__/role.test.js.snap
@@ -66,7 +66,7 @@ exports[`role role and group should render correctly with router 1`] = `
class="pf-v5-l-flex pf-m-justify-content-space-between"
>