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: [UIE-8139] - IAM RBAC: add new assigned entities table component part 1 #11588

Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/api-v4": Upcoming Features
---

updated types for iam ([#11588](https://github.com/linode/manager/pull/11588))
1 change: 1 addition & 0 deletions packages/api-v4/src/iam/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export type RoleType =
| 'linode_viewer'
| 'firewall_admin'
| 'linode_creator'
| 'update_firewall'
| 'firewall_creator';

export interface IamUserPermissions {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Upcoming Features
---

add new table component for the assigned entities in the iam ([#11588](https://github.com/linode/manager/pull/11588))
5 changes: 5 additions & 0 deletions packages/manager/src/factories/userPermissions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ export const userPermissionsFactory = Factory.Sync.makeFactory<IamUserPermission
resource_type: 'linode',
roles: ['linode_contributor', 'linode_viewer'],
},
{
resource_id: 45678901,
resource_type: 'firewall',
roles: ['update_firewall'],
},
],
}
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import { fireEvent, waitFor } from '@testing-library/react';
import React from 'react';

import { accountResourcesFactory } from 'src/factories/accountResources';
import { userPermissionsFactory } from 'src/factories/userPermissions';
import { renderWithTheme } from 'src/utilities/testHelpers';

import { AssignedEntitiesTable } from './AssignedEntitiesTable';

const queryMocks = vi.hoisted(() => ({
useAccountResources: vi.fn().mockReturnValue({}),
useAccountUserPermissions: vi.fn().mockReturnValue({}),
}));

vi.mock('src/queries/iam/iam', async () => {
const actual = await vi.importActual<any>('src/queries/iam/iam');
return {
...actual,
useAccountUserPermissions: queryMocks.useAccountUserPermissions,
};
});

vi.mock('src/queries/resources/resources', async () => {
const actual = await vi.importActual<any>('src/queries/resources/resources');
return {
...actual,
useAccountResources: queryMocks.useAccountResources,
};
});

describe('AssignedEntitiesTable', () => {
it('should display no roles text if there are no roles assigned to user', async () => {
queryMocks.useAccountUserPermissions.mockReturnValue({
data: {},
});

const { getByText } = renderWithTheme(<AssignedEntitiesTable />);

getByText('No Entities are assigned.');
});

it('should display roles and menu when data is available', async () => {
queryMocks.useAccountUserPermissions.mockReturnValue({
data: userPermissionsFactory.build(),
});

queryMocks.useAccountResources.mockReturnValue({
data: accountResourcesFactory.build(),
});

const { getAllByLabelText, getByText } = renderWithTheme(
<AssignedEntitiesTable />
);

expect(getByText('firewall-us-123')).toBeInTheDocument();
expect(getByText('Firewall')).toBeInTheDocument();
expect(getByText('update_firewall')).toBeInTheDocument();

const actionMenuButton = getAllByLabelText('action menu')[0];
expect(actionMenuButton).toBeInTheDocument();

fireEvent.click(actionMenuButton);
expect(getByText('Change Role')).toBeInTheDocument();
expect(getByText('Remove Assignment')).toBeInTheDocument();
});

it('should display empty state when no roles match filters', async () => {
queryMocks.useAccountUserPermissions.mockReturnValue({
data: userPermissionsFactory.build(),
});

queryMocks.useAccountResources.mockReturnValue({
data: accountResourcesFactory.build(),
});

const { getByPlaceholderText, getByText } = renderWithTheme(
<AssignedEntitiesTable />
);

const searchInput = getByPlaceholderText('Search');
fireEvent.change(searchInput, { target: { value: 'NonExistentRole' } });

await waitFor(() => {
expect(getByText('No Entities are assigned.')).toBeInTheDocument();
});
});

it('should filter roles based on search query', async () => {
queryMocks.useAccountUserPermissions.mockReturnValue({
data: userPermissionsFactory.build(),
});

queryMocks.useAccountResources.mockReturnValue({
data: accountResourcesFactory.build(),
});

const { getByPlaceholderText, queryByText } = renderWithTheme(
<AssignedEntitiesTable />
);

const searchInput = getByPlaceholderText('Search');
fireEvent.change(searchInput, {
target: { value: 'firewall-us-123' },
});

await waitFor(() => {
expect(queryByText('firewall-us-123')).toBeInTheDocument();
});
});

it('should filter roles based on selected resource type', async () => {
queryMocks.useAccountUserPermissions.mockReturnValue({
data: userPermissionsFactory.build(),
});

queryMocks.useAccountResources.mockReturnValue({
data: accountResourcesFactory.build(),
});

const { getByPlaceholderText, queryByText } = renderWithTheme(
<AssignedEntitiesTable />
);

const autocomplete = getByPlaceholderText('All Assigned Entities');
fireEvent.change(autocomplete, { target: { value: 'Firewalls' } });

await waitFor(() => {
expect(queryByText('firewall-us-123')).toBeInTheDocument();
});
});
});
Loading