-
Notifications
You must be signed in to change notification settings - Fork 7
feat(authz): add team members table with sorting, pagination and filtering. #124
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
Merged
Merged
Changes from 13 commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
acb42de
feat: roles and permissions tab added
jesusbalderramawgu c109062
feat: refactor to create new path for roles permissions tab
jesusbalderramawgu 896f6a7
feat: icons added to roles
jesusbalderramawgu 8198428
chore: lint fix
jesusbalderramawgu 7e062a5
chore: fix texts and removed unnecessary validations
jesusbalderramawgu 8f38e60
chore: aria labels updated
jesusbalderramawgu 257681e
chore: missing i18n added, tests updated
jesusbalderramawgu de0cf3e
chore: unnecessary path removed
jesusbalderramawgu 59659e3
feat: disable columns and tooltip added
jesusbalderramawgu 072542c
feat: creating the team members tab with the new ui
jacobo-dominguez-wgu ad413a3
feat: integrating backend apis into team members table
jacobo-dominguez-wgu d6ea3d9
test: adding new ut for new team members table an its components
jacobo-dominguez-wgu 0fa970f
feat: adding show more text on filters and description text
jacobo-dominguez-wgu b5941f5
fix: addressing pr comments
jacobo-dominguez-wgu 2d51fee
chore: unnecessary test deleted
jesusbalderramawgu File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,6 +1,8 @@ | ||||||
| import { useIntl } from '@edx/frontend-platform/i18n'; | ||||||
| import { Tab, Tabs } from '@openedx/paragon'; | ||||||
| import { useLocation } from 'react-router-dom'; | ||||||
| import { useLocation, useSearchParams } from 'react-router-dom'; | ||||||
| import TeamMembersTable from '@src/authz-module/team-members/TeamMembersTable'; | ||||||
| import AddRoleButton from '@src/authz-module/components/AddRoleButton'; | ||||||
| import RolesPermissions from '../roles-permissions/RolesPermissions'; | ||||||
| import AuthZLayout from '../components/AuthZLayout'; | ||||||
|
|
||||||
|
|
@@ -9,8 +11,10 @@ import messages from './messages'; | |||||
| const AuthzHome = () => { | ||||||
| const { hash } = useLocation(); | ||||||
| const intl = useIntl(); | ||||||
| const [searchParams] = useSearchParams(); | ||||||
| const presetScope = searchParams.get('scope') || undefined; | ||||||
|
|
||||||
| const rootBreadcrumb = intl.formatMessage(messages['authz.breadcrumb.root']) || ''; | ||||||
| const rootBreadcrumb = intl.formatMessage(messages['authz.breadcrumb.root']); | ||||||
| const pageTitle = intl.formatMessage(messages['authz.manage.page.title']); | ||||||
|
|
||||||
| return ( | ||||||
|
|
@@ -22,11 +26,7 @@ const AuthzHome = () => { | |||||
| pageTitle={pageTitle} | ||||||
| pageSubtitle="" | ||||||
| actions={ | ||||||
| [] | ||||||
| // this needs to be enable again once is refactored to be used outside of library context | ||||||
| // [ | ||||||
| // <AddNewTeamMemberTrigger libraryId="" key="add-new-member" />, | ||||||
| // ] | ||||||
| [<AddRoleButton key="add-role-button" />] | ||||||
| } | ||||||
| > | ||||||
| <Tabs | ||||||
|
|
@@ -35,8 +35,7 @@ const AuthzHome = () => { | |||||
| className="bg-light-100 px-5" | ||||||
| > | ||||||
| <Tab eventKey="team" title={intl.formatMessage(messages['authz.tabs.team'])} className="p-5"> | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| {/* TODO: once TeamTable is refactored we can call it here. For now, this tab will be empty. */} | ||||||
| {/* <TeamTable /> */} | ||||||
| <TeamMembersTable presetScope={presetScope} /> | ||||||
| </Tab> | ||||||
| <Tab id="libraries-permissions-roles-tab" eventKey="permissionsRoles" title={intl.formatMessage(messages['authz.tabs.permissionsRoles'])}> | ||||||
| <RolesPermissions /> | ||||||
|
|
||||||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,134 @@ | ||
| import { screen } from '@testing-library/react'; | ||
| import userEvent from '@testing-library/user-event'; | ||
| import { useNavigate } from 'react-router-dom'; | ||
| import { initializeMockApp } from '@edx/frontend-platform/testing'; | ||
| import { renderWrapper } from '@src/setupTest'; | ||
| import AddRoleButton from './AddRoleButton'; | ||
|
|
||
| // Mock react-router-dom navigation | ||
| jest.mock('react-router-dom', () => ({ | ||
| ...jest.requireActual('react-router-dom'), | ||
| useNavigate: jest.fn(), | ||
| })); | ||
|
|
||
| describe('AddRoleButton', () => { | ||
| const mockNavigate = jest.fn(); | ||
|
|
||
| beforeAll(() => { | ||
| initializeMockApp({ | ||
| authenticatedUser: { | ||
| userId: 1, | ||
| username: 'testuser', | ||
| email: '[email protected]', | ||
| }, | ||
| }); | ||
| }); | ||
|
|
||
| beforeEach(() => { | ||
| (useNavigate as jest.Mock).mockReturnValue(mockNavigate); | ||
| }); | ||
|
|
||
| afterEach(() => { | ||
| jest.clearAllMocks(); | ||
| }); | ||
|
|
||
| describe('rendering', () => { | ||
| it('renders the assign role button with correct text', () => { | ||
| renderWrapper(<AddRoleButton />); | ||
|
|
||
| const button = screen.getByRole('button', { name: /assign role/i }); | ||
| expect(button).toBeInTheDocument(); | ||
| }); | ||
|
|
||
| it('displays the plus icon', () => { | ||
| renderWrapper(<AddRoleButton />); | ||
|
|
||
| const button = screen.getByRole('button', { name: /assign role/i }); | ||
| expect(button.querySelector('svg')).toBeInTheDocument(); | ||
| }); | ||
|
|
||
| it('renders correctly when presetUsername is provided', () => { | ||
| renderWrapper(<AddRoleButton presetUsername="testuser123" />); | ||
|
|
||
| const button = screen.getByRole('button', { name: /assign role/i }); | ||
| expect(button).toBeInTheDocument(); | ||
| }); | ||
| }); | ||
|
|
||
| describe('navigation behavior', () => { | ||
| it('navigates to assign role page without username when clicked', async () => { | ||
| const user = userEvent.setup(); | ||
| renderWrapper(<AddRoleButton />); | ||
|
|
||
| const button = screen.getByRole('button', { name: /assign role/i }); | ||
| await user.click(button); | ||
|
|
||
| expect(mockNavigate).toHaveBeenCalledTimes(1); | ||
| expect(mockNavigate).toHaveBeenCalledWith('/authz/assign-role'); | ||
| }); | ||
|
|
||
| it('navigates to assign role page with username query parameter when presetUsername is provided', async () => { | ||
| const user = userEvent.setup(); | ||
| const presetUsername = 'john.doe'; | ||
| renderWrapper(<AddRoleButton presetUsername={presetUsername} />); | ||
|
|
||
| const button = screen.getByRole('button', { name: /assign role/i }); | ||
| await user.click(button); | ||
|
|
||
| expect(mockNavigate).toHaveBeenCalledTimes(1); | ||
| expect(mockNavigate).toHaveBeenCalledWith(`/authz/assign-role?username=${presetUsername}`); | ||
| }); | ||
|
|
||
| it('handles special characters in presetUsername correctly', async () => { | ||
| const user = userEvent.setup(); | ||
| const presetUsername = '[email protected]'; | ||
| renderWrapper(<AddRoleButton presetUsername={presetUsername} />); | ||
|
|
||
| const button = screen.getByRole('button', { name: /assign role/i }); | ||
| await user.click(button); | ||
|
|
||
| expect(mockNavigate).toHaveBeenCalledTimes(1); | ||
| expect(mockNavigate).toHaveBeenCalledWith(`/authz/assign-role?username=${presetUsername}`); | ||
| }); | ||
| }); | ||
|
|
||
| describe('user interactions', () => { | ||
| it('responds to keyboard navigation', async () => { | ||
| const user = userEvent.setup(); | ||
| renderWrapper(<AddRoleButton />); | ||
|
|
||
| const button = screen.getByRole('button', { name: /assign role/i }); | ||
|
|
||
| await user.tab(); | ||
| expect(button).toHaveFocus(); | ||
|
|
||
| await user.keyboard('{Enter}'); | ||
| expect(mockNavigate).toHaveBeenCalledWith('/authz/assign-role'); | ||
| }); | ||
|
|
||
| it('responds to spacebar activation', async () => { | ||
| const user = userEvent.setup(); | ||
| renderWrapper(<AddRoleButton />); | ||
|
|
||
| const button = screen.getByRole('button', { name: /assign role/i }); | ||
| button.focus(); | ||
|
|
||
| await user.keyboard(' '); | ||
| expect(mockNavigate).toHaveBeenCalledWith('/authz/assign-role'); | ||
| }); | ||
|
|
||
| it('handles multiple clicks gracefully', async () => { | ||
| const user = userEvent.setup(); | ||
| renderWrapper(<AddRoleButton presetUsername="testuser" />); | ||
|
|
||
| const button = screen.getByRole('button', { name: /assign role/i }); | ||
|
|
||
| await user.click(button); | ||
| await user.click(button); | ||
| await user.click(button); | ||
|
|
||
| expect(mockNavigate).toHaveBeenCalledTimes(3); | ||
| expect(mockNavigate).toHaveBeenCalledWith('/authz/assign-role?username=testuser'); | ||
| }); | ||
| }); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| import React from 'react'; | ||
| import { useIntl } from '@edx/frontend-platform/i18n'; | ||
| import { Button } from '@openedx/paragon'; | ||
| import { Plus } from '@openedx/paragon/icons'; | ||
|
|
||
| import baseMessages from '@src/authz-module/messages'; | ||
| import { useNavigate } from 'react-router-dom'; | ||
|
|
||
| interface AddRoleButtonProps { | ||
| presetUsername?: string; | ||
| } | ||
|
|
||
| const AddRoleButton = ({ presetUsername }: AddRoleButtonProps) => { | ||
| const intl = useIntl(); | ||
| const navigate = useNavigate(); | ||
|
|
||
| const handleClick = () => { | ||
| const assignRolePath = `/authz/assign-role${presetUsername ? `?username=${presetUsername}` : ''}`; | ||
| navigate(assignRolePath); | ||
| }; | ||
|
|
||
| return ( | ||
| <Button | ||
| iconBefore={Plus} | ||
| onClick={handleClick} | ||
| > | ||
| {intl.formatMessage(baseMessages['authz.management.assign.role.title'])} | ||
| </Button> | ||
| ); | ||
| }; | ||
|
|
||
| export default AddRoleButton; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lets try to avoid mocking components, you can setup the test:
And just test the accessibility assertions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have refactored the tests to stop mocking components and focus on user centric assertions.