Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 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
9 changes: 9 additions & 0 deletions apps/meteor/client/components/UserInfo/UserInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
import MarkdownText from '../MarkdownText';
import UTCClock from '../UTCClock';
import { UserCardRoles } from '../UserCard';
import UserInfoABACAttributes from './UserInfoABACAttributes';
import UserInfoAvatar from './UserInfoAvatar';

type UserInfoDataProps = Serialized<
Expand Down Expand Up @@ -70,6 +71,8 @@ const UserInfo = ({
canViewAllInfo,
actions,
reason,
// @ts-expect-error - abacAttributes is not yet implemented in Users properties
abacAttributes = null,
...props
}: UserInfoProps): ReactElement => {
const { t } = useTranslation();
Expand Down Expand Up @@ -175,6 +178,12 @@ const UserInfo = ({
</InfoPanelField>
)}

{abacAttributes && abacAttributes.length > 0 && (
<InfoPanelField>
<InfoPanelLabel title={t('ABAC_Attributes_description')}>{t('ABAC_Attributes')}</InfoPanelLabel>
<UserInfoABACAttributes abacAttributes={abacAttributes} />
</InfoPanelField>
)}
{userCustomFields?.map(
(customField) =>
customField?.value && (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Tag } from '@rocket.chat/fuselage';
import type { ReactElement } from 'react';

type UserInfoABACAttributeProps = {
attribute: string;
};

const UserInfoABACAttribute = ({ attribute }: UserInfoABACAttributeProps): ReactElement => {
return <Tag variant='secondary-warning' children={attribute} />;
Comment thread
MartinSchoeler marked this conversation as resolved.
};

export default UserInfoABACAttribute;
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { mockAppRoot } from '@rocket.chat/mock-providers';
import { render, screen } from '@testing-library/react';
import { axe } from 'jest-axe';

import UserInfoABACAttributes from './UserInfoABACAttributes';

const appRoot = mockAppRoot()
.withTranslations('en', 'core', {
ABAC_attributes: 'ABAC Attributes',
Comment thread
MartinSchoeler marked this conversation as resolved.
Outdated
ABAC_Attributes_description: 'Attribute-Based Access Control',
})
.build();

describe('UserInfoABACAttributes', () => {
it('should render with multiple attributes', () => {
const attributes = ['Classified', 'Top Secret', 'Confidential'];
const { baseElement } = render(<UserInfoABACAttributes abacAttributes={attributes} />, { wrapper: appRoot });

expect(baseElement).toMatchSnapshot();
expect(screen.getByText('Classified')).toBeInTheDocument();
expect(screen.getByText('Top Secret')).toBeInTheDocument();
expect(screen.getByText('Confidential')).toBeInTheDocument();
});

it('should have no accessibility violations with multiple attributes', async () => {
const attributes = ['Classified', 'Top Secret', 'Confidential'];
const { container } = render(<UserInfoABACAttributes abacAttributes={attributes} />, { wrapper: appRoot });

const results = await axe(container);
expect(results).toHaveNoViolations();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { mockAppRoot } from '@rocket.chat/mock-providers';
import type { Meta, StoryObj } from '@storybook/react';

import UserInfoABACAttributes from './UserInfoABACAttributes';

const meta = {
component: UserInfoABACAttributes,
parameters: {
layout: 'centered',
},
args: {
abacAttributes: ['Classified', 'Top Secret', 'Confidential'],
},
decorators: [
(Story) => {
const AppRoot = mockAppRoot()
.withTranslations('en', 'core', {
ABAC_attributes: 'ABAC Attributes',
ABAC_Attributes_description: 'Attribute-Based Access Control',
})
.build();

return (
<AppRoot>
<Story />
</AppRoot>
);
},
],
} satisfies Meta<typeof UserInfoABACAttributes>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Default: Story = {
args: {
abacAttributes: ['Top Secret', 'Classified', 'Confidential', 'Restricted', 'Internal'],
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Box, Margins } from '@rocket.chat/fuselage';
import type { ComponentProps, ReactElement } from 'react';

import UserInfoABACAttribute from './UserInfoABACAttribute';

type UserCardABACAttributesProps = {
abacAttributes: string[];
} & ComponentProps<typeof Box>;
Comment thread
MartinSchoeler marked this conversation as resolved.
Outdated

const UserInfoABACAttributes = ({ abacAttributes }: UserCardABACAttributesProps): ReactElement => {
Comment thread
MartinSchoeler marked this conversation as resolved.
Outdated
return (
Comment thread
MartinSchoeler marked this conversation as resolved.
<Box flexWrap='wrap' display='flex'>
{abacAttributes.map((attribute, index) => (
<Margins inline={2} blockEnd={4} key={index}>
Comment thread
MartinSchoeler marked this conversation as resolved.
Outdated
<UserInfoABACAttribute attribute={attribute} />
</Margins>
))}
</Box>
);
};

export default UserInfoABACAttributes;
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing

exports[`UserInfoABACAttributes should render with multiple attributes 1`] = `
<body>
<div>
<span
class="rcx-box rcx-box--full rcx-css-zr2f9f"
>
<span
class="rcx-box rcx-box--full rcx-tag rcx-tag--secondary-warning rcx-css-wcp0mp"
>
<span
class="rcx-tag__inner"
>
Classified
</span>
</span>
<span
class="rcx-box rcx-box--full rcx-tag rcx-tag--secondary-warning rcx-css-wcp0mp"
>
<span
class="rcx-tag__inner"
>
Top Secret
</span>
</span>
<span
class="rcx-box rcx-box--full rcx-tag rcx-tag--secondary-warning rcx-css-wcp0mp"
>
<span
class="rcx-tag__inner"
>
Confidential
</span>
</span>
</span>
</div>
</body>
`;
2 changes: 2 additions & 0 deletions packages/i18n/src/locales/en.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -698,6 +698,8 @@
"Attribute_based_access_control": "Attribute-Based Access Control",
"Attribute_based_access_control_title": "Automate complex access management across your entire organization",
"Attribute_based_access_control_description": "ABAC automates room access, granting or revoking access based on dynamic user attributes rather than fixed roles.",
"ABAC_Attributes": "Subject attributes",
"ABAC_Attributes_description": "User characteristics ABAC uses to determine room access",
"Audio": "Audio",
"Audio_Notification_Value_Description": "Can be any custom sound or the default ones: beep, chelle, ding, droplet, highbell, seasons",
"Audio_Notifications_Default_Alert": "Audio Notifications Default Alert",
Expand Down
Loading