Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(RolesTable): add sorting and filtering #1728

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 121 additions & 1 deletion cypress/e2e/roles.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,109 @@ describe('Roles page', () => {
external_role_id: null,
external_tenant: null,
},
{
uuid: '00000-00000-1111-1111-111111',
name: 'A_Test_00000-00000',
display_name: 'A Test',
description: 'Test role A',
created: '2024-05-17T05:03:15.684013Z',
modified: '2024-05-17T05:03:15.709410Z',
policyCount: 2,
accessCount: 2,
applications: [],
system: false,
platform_default: false,
admin_default: false,
external_role_id: null,
external_tenant: null,
},
],
meta: {
count: 3,
limit: 20,
offset: 0,
},
};

const sortedRoles = {
data: [
{
uuid: '00000-00000-1111-1111-111111',
name: 'A_Test_00000-00000',
display_name: 'A Test',
description: 'Test role A',
created: '2024-05-17T05:03:15.684013Z',
modified: '2024-05-17T05:03:15.709410Z',
policyCount: 2,
accessCount: 2,
applications: [],
system: false,
platform_default: false,
admin_default: false,
external_role_id: null,
external_tenant: null,
},
{
uuid: '00000-0000-0000-0000-00000000',
name: 'Test_1_00000-00000',
display_name: 'Test 1',
description: 'Test role1',
created: '2024-05-17T05:03:15.684013Z',
modified: '2024-05-17T05:03:15.709410Z',
policyCount: 2,
accessCount: 2,
applications: [],
system: false,
platform_default: false,
admin_default: false,
external_role_id: null,
external_tenant: null,
},
{
uuid: '00000-11111-1111-1111-111111',
name: 'Test_2_00000-00000',
display_name: 'Test 2',
description: 'Test role2',
created: '2024-05-17T05:03:15.684013Z',
modified: '2024-05-17T05:03:15.709410Z',
policyCount: 2,
accessCount: 2,
applications: [],
system: false,
platform_default: false,
admin_default: false,
external_role_id: null,
external_tenant: null,
},
],
meta: {
count: 2,
count: 3,
limit: 20,
offset: 0,
},
};

const filteredRoles = {
data: [
{
uuid: '00000-00000-1111-1111-111111',
name: 'A_Test_00000-00000',
display_name: 'A Test',
description: 'Test role A',
created: '2024-05-17T05:03:15.684013Z',
modified: '2024-05-17T05:03:15.709410Z',
policyCount: 2,
accessCount: 2,
applications: [],
system: false,
platform_default: false,
admin_default: false,
external_role_id: null,
external_tenant: null,
},
],
meta: {
count: 1,
limit: 20,
offset: 0,
},
Expand Down Expand Up @@ -85,4 +185,24 @@ describe('Roles page', () => {
cy.get('[data-ouia-component-id^="RolesTable-assigned-groups-tab"]').first().click();
cy.get('[data-ouia-component-id^="assigned-usergroups-table-stack"]').should('be.visible');
});

it('should sort roles', () => {
cy.intercept('GET', '**/api/rbac/v1/roles/?limit=20&display_name=&scope=org_id&order_by=display_name*', {
statusCode: 200,
body: sortedRoles,
}).as('sortRoles');
cy.get('[data-ouia-component-id="RolesTable-table-th-0"]').click();
cy.wait('@sortRoles', { timeout: 15000 });
cy.get('[data-ouia-component-id="RolesTable-table-td-0-0"]').should('contain.text', 'A Test');
});

it('should filter roles by name', () => {
cy.intercept('GET', '**/api/rbac/v1/roles/?limit=20&display_name=A*', {
statusCode: 200,
body: filteredRoles,
}).as('filterRoles');
cy.get('[data-ouia-component-id="RolesTable-name-filter-input"]').type('A');
cy.wait('@filterRoles', { timeout: 15000 });
cy.get('table tbody tr').should('have.length', 1);
});
});
4 changes: 4 additions & 0 deletions cypress/support/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ Cypress.Commands.add('login', (enableWorkspaces = false) => {
// This JS file causes randomly an uncaught exception on login page which blocks the tests
// Cannot read properties of undefined (reading 'setAttribute')
cy.intercept({ url: 'https://sso.stage.redhat.com/auth/resources/0833r/login/rhd-theme/dist/pfelements/bundle.js' }, {});
Cypress.on('uncaught:exception', (err) => {
console.log(err);
return false;
});
cy.visit('/');
// disable analytics integrations
cy.setLocalStorage('chrome:analytics:disable', 'true');
Expand Down
9 changes: 4 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"@patternfly/quickstarts": "^5.1.0",
"@patternfly/react-component-groups": "^5.5.5",
"@patternfly/react-core": "^5.1.1",
"@patternfly/react-data-view": "^5.7.0",
"@patternfly/react-data-view": "^5.7.1",
"@patternfly/react-icons": "^5.1.1",
"@patternfly/react-table": "^5.1.1",
"@patternfly/react-tokens": "^5.1.1",
Expand Down
44 changes: 22 additions & 22 deletions src/smart-components/access-management/UserGroupsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import messages from '../../Messages';
import { Group } from '../../redux/reducers/group-reducer';
import { DataViewTrObject, DataViewState, EventTypes, useDataViewEventsContext } from '@patternfly/react-data-view';
import { SearchIcon } from '@patternfly/react-icons';
import { ResponsiveAction, ResponsiveActions, SkeletonTableBody, WarningModal } from '@patternfly/react-component-groups';
import { ResponsiveAction, ResponsiveActions, SkeletonTableBody, SkeletonTableHead, WarningModal } from '@patternfly/react-component-groups';
import AddGroupWizard from '../group/add-group/add-group-wizard';

const COLUMNS: string[] = ['User group name', 'Description', 'Users', 'Service accounts', 'Roles', 'Workspaces', 'Last modified'];
Expand All @@ -30,6 +30,25 @@ const PER_PAGE_OPTIONS = [
{ title: '100', value: 100 },
];

const EmptyTable: React.FunctionComponent<{ titleText: string }> = ({ titleText }) => {
return (
<EmptyState>
<EmptyStateHeader titleText={titleText} headingLevel="h4" icon={<EmptyStateIcon icon={SearchIcon} />} />
<EmptyStateBody>
<FormattedMessage
{...messages['usersEmptyStateSubtitle']}
values={{
br: <br />,
}}
/>
</EmptyStateBody>
</EmptyState>
);
};

const loadingHeader = <SkeletonTableHead columns={COLUMNS} />;
const loadingBody = <SkeletonTableBody rowsCount={10} columnsCount={COLUMNS.length} />;

interface UserGroupsTableProps {
defaultPerPage?: number;
useUrlParams?: boolean;
Expand Down Expand Up @@ -207,26 +226,6 @@ const UserGroupsTable: React.FunctionComponent<UserGroupsTableProps> = ({
/>
);

const empty = (
<EmptyState>
<EmptyStateHeader
titleText={intl.formatMessage(messages.userGroupsEmptyStateTitle)}
headingLevel="h4"
icon={<EmptyStateIcon icon={SearchIcon} />}
/>
<EmptyStateBody>
<FormattedMessage
{...messages['userGroupsEmptyStateSubtitle']}
values={{
br: <br />,
}}
/>
</EmptyStateBody>
</EmptyState>
);

const loading = <SkeletonTableBody rowsCount={10} columnsCount={COLUMNS.length + 1} isSelectable />;

return (
<Fragment>
{isAddGroupWizardOpen && (
Expand Down Expand Up @@ -302,7 +301,8 @@ const UserGroupsTable: React.FunctionComponent<UserGroupsTableProps> = ({
ouiaId={`${ouiaId}-table`}
columns={COLUMNS}
rows={rows}
bodyStates={{ empty, loading }}
headStates={{ loading: loadingHeader }}
bodyStates={{ loading: loadingBody, empty: <EmptyTable titleText={intl.formatMessage(messages.userGroupsEmptyStateTitle)} /> }}
/>
<DataViewToolbar ouiaId={`${ouiaId}-footer-toolbar`} pagination={paginationComponent} />
</DataView>
Expand Down
40 changes: 22 additions & 18 deletions src/smart-components/access-management/UsersTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { User } from '../../redux/reducers/user-reducer';
import { FormattedMessage, useIntl } from 'react-intl';
import messages from '../../Messages';
import { Outlet, useSearchParams } from 'react-router-dom';
import { SkeletonTableBody, WarningModal } from '@patternfly/react-component-groups';
import { SkeletonTableBody, SkeletonTableHead, 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';
Expand All @@ -33,6 +33,25 @@ const PER_PAGE_OPTIONS = [
{ title: '100', value: 100 },
];

const EmptyTable: React.FunctionComponent<{ titleText: string }> = ({ titleText }) => {
return (
<EmptyState>
<EmptyStateHeader titleText={titleText} headingLevel="h4" icon={<EmptyStateIcon icon={SearchIcon} />} />
<EmptyStateBody>
<FormattedMessage
{...messages['usersEmptyStateSubtitle']}
values={{
br: <br />,
}}
/>
</EmptyStateBody>
</EmptyState>
);
};

const loadingHeader = <SkeletonTableHead columns={COLUMNS} />;
const loadingBody = <SkeletonTableBody rowsCount={10} columnsCount={COLUMNS.length} />;

const OUIA_ID = 'iam-users-table';

interface UsersTableProps {
Expand Down Expand Up @@ -159,22 +178,6 @@ const UsersTable: React.FunctionComponent<UsersTableProps> = ({ onAddUserClick,
/>
);

const empty = (
<EmptyState>
<EmptyStateHeader titleText={intl.formatMessage(messages.usersEmptyStateTitle)} headingLevel="h4" icon={<EmptyStateIcon icon={SearchIcon} />} />
<EmptyStateBody>
<FormattedMessage
{...messages['usersEmptyStateSubtitle']}
values={{
br: <br />,
}}
/>
</EmptyStateBody>
</EmptyState>
);

const loading = <SkeletonTableBody rowsCount={10} columnsCount={COLUMNS.length + 1} isSelectable />;

return (
<Fragment>
{isDeleteModalOpen && (
Expand Down Expand Up @@ -239,7 +242,8 @@ const UsersTable: React.FunctionComponent<UsersTableProps> = ({ onAddUserClick,
ouiaId={`${OUIA_ID}-table`}
columns={COLUMNS}
rows={rows}
bodyStates={{ empty, loading }}
headStates={{ loading: loadingHeader }}
bodyStates={{ loading: loadingBody, empty: <EmptyTable titleText={intl.formatMessage(messages.usersEmptyStateTitle)} /> }}
/>
<DataViewToolbar ouiaId={`${OUIA_ID}-footer-toolbar`} pagination={paginationComponent} />
</DataView>
Expand Down
Loading
Loading