Skip to content

Commit 287f302

Browse files
chore: Header tags for ABAC rooms (#37126)
1 parent 3309f90 commit 287f302

File tree

10 files changed

+153
-2
lines changed

10 files changed

+153
-2
lines changed
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import type { IRoom } from '@rocket.chat/apps-engine/definition/rooms';
2+
import { mockAppRoot } from '@rocket.chat/mock-providers';
3+
import { render, screen } from '@testing-library/react';
4+
import { axe } from 'jest-axe';
5+
6+
import ABACHeaderTag from './ABACHeaderTag';
7+
8+
const appRoot = mockAppRoot()
9+
.withTranslations('en', 'core', {
10+
ABAC_header_tag_title: 'Only compliant users have access to attribute-based access controlled rooms.',
11+
ABAC_header_tag: 'ABAC',
12+
})
13+
.build();
14+
15+
const createMockRoom = (overrides: Partial<IRoom> = {}) => ({
16+
_id: 'room-id',
17+
t: 'c' as const,
18+
name: 'test-room',
19+
msgs: 0,
20+
u: { _id: 'user-id', username: 'testuser' },
21+
usersCount: 1,
22+
_updatedAt: new Date(),
23+
...overrides,
24+
});
25+
26+
describe('ABACHeaderTag', () => {
27+
it('should render the ABAC tag when room has ABAC attributes', () => {
28+
const room = createMockRoom({
29+
// @ts-expect-error to be implemented
30+
abacAttributes: { someAttribute: 'value' },
31+
});
32+
33+
const { baseElement } = render(<ABACHeaderTag room={room} />, { wrapper: appRoot });
34+
expect(baseElement).toMatchSnapshot();
35+
});
36+
37+
it('should not render when room has no ABAC attributes', () => {
38+
const room = createMockRoom();
39+
40+
render(<ABACHeaderTag room={room} />, { wrapper: appRoot });
41+
expect(screen.queryByText('ABAC')).not.toBeInTheDocument();
42+
});
43+
44+
it('should have no accessibility violations when rendered', async () => {
45+
const room = createMockRoom({
46+
// @ts-expect-error to be implemented
47+
abacAttributes: { someAttribute: 'value' },
48+
});
49+
50+
const { container } = render(<ABACHeaderTag room={room} />, { wrapper: appRoot });
51+
const results = await axe(container);
52+
expect(results).toHaveNoViolations();
53+
});
54+
55+
it('should have no accessibility violations when not rendered', async () => {
56+
const room = createMockRoom();
57+
58+
const { container } = render(<ABACHeaderTag room={room} />, { wrapper: appRoot });
59+
const results = await axe(container);
60+
expect(results).toHaveNoViolations();
61+
});
62+
});
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import type { IRoom } from '@rocket.chat/core-typings';
2+
import { Box, Palette } from '@rocket.chat/fuselage';
3+
import { useTranslation } from 'react-i18next';
4+
5+
import { HeaderTag } from '../Header';
6+
7+
type ABACHeaderTagProps = {
8+
room: IRoom;
9+
};
10+
11+
const ABACHeaderTag = ({ room }: ABACHeaderTagProps) => {
12+
const { t } = useTranslation();
13+
14+
// @ts-expect-error to be implemented
15+
if (!room.abacAttributes) {
16+
return null;
17+
}
18+
19+
return (
20+
<HeaderTag title={t('ABAC_header_tag_title')}>
21+
<Box color={Palette.statusColor['status-font-on-warning'].toString()} fontWeight='700'>
22+
{t('ABAC_header_tag')}
23+
</Box>
24+
</HeaderTag>
25+
);
26+
};
27+
28+
export default ABACHeaderTag;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
2+
3+
exports[`ABACHeaderTag should render the ABAC tag when room has ABAC attributes 1`] = `
4+
<body>
5+
<div>
6+
<div
7+
class="rcx-box rcx-box--full rcx-css-1kopyx3"
8+
>
9+
<span
10+
class="rcx-box rcx-box--full rcx-tag rcx-tag--medium"
11+
title="Only compliant users have access to attribute-based access controlled rooms."
12+
>
13+
<span
14+
class="rcx-tag__inner"
15+
>
16+
<div
17+
class="rcx-box rcx-box--full rcx-css-12a8uky"
18+
>
19+
ABAC
20+
</div>
21+
</span>
22+
</span>
23+
</div>
24+
</div>
25+
</body>
26+
`;

apps/meteor/client/views/room/Header/RoomHeader.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import RoomToolbox from './RoomToolbox';
1313
import Encrypted from './icons/Encrypted';
1414
import Favorite from './icons/Favorite';
1515
import Translate from './icons/Translate';
16+
import ABACHeaderTag from '../../../components/ABAC/ABACHeaderTag';
1617
import { Header, HeaderAvatar, HeaderContent, HeaderContentRow, HeaderSubtitle, HeaderToolbar } from '../../../components/Header';
1718
import MarkdownText from '../../../components/MarkdownText';
1819

@@ -50,6 +51,7 @@ const RoomHeader = ({ room, topic = '', slots = {}, roomToolbox }: RoomHeaderPro
5051
<Favorite room={room} />
5152
{room.prid && <ParentRoomWithData room={room} />}
5253
{room.teamId && !room.teamMain && <ParentTeam room={room} />}
54+
<ABACHeaderTag room={room} />
5355
{isRoomFederated(room) && <FederatedRoomOriginServer room={room} />}
5456
<Encrypted room={room} />
5557
<Translate room={room} />

apps/meteor/client/views/room/HeaderV2/RoomHeader.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import RoomTopic from './RoomTopic';
1212
import Encrypted from './icons/Encrypted';
1313
import Favorite from './icons/Favorite';
1414
import Translate from './icons/Translate';
15+
import ABACHeaderTag from '../../../components/ABAC/ABACHeaderTag';
1516
import { Header, HeaderContent, HeaderContentRow, HeaderToolbar } from '../../../components/Header';
1617

1718
export type RoomHeaderProps = {
@@ -43,6 +44,7 @@ const RoomHeader = ({ room, slots = {}, roomToolbox }: RoomHeaderProps) => {
4344
<HeaderContentRow>
4445
<RoomTitle room={room} />
4546
<Favorite room={room} />
47+
<ABACHeaderTag room={room} />
4648
{isRoomFederated(room) && <FederatedRoomOriginServer room={room} />}
4749
<Encrypted room={room} />
4850
<Translate room={room} />

packages/i18n/src/locales/en.i18n.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@
7777
"A_new_owner_will_be_assigned_automatically_to_those__count__rooms__rooms__": "A new owner will be assigned automatically to those <bold>{{count}}</bold> rooms:<br/> {{rooms}}.",
7878
"A_secure_and_highly_private_self-managed_solution_for_conference_calls": "A secure and highly private self-managed solution for conference calls.",
7979
"A_workspace_admin_needs_to_install_and_configure_a_conference_call_app": "A workspace admin needs to install and configure a conference call app.",
80+
"ABAC_header_tag_title": "Only compliant users have access to attribute-based access controlled rooms.",
81+
"ABAC_header_tag": "ABAC",
8082
"Accept": "Accept",
8183
"Accept_Call": "Accept Call",
8284
"Accept_incoming_livechat_requests_even_if_there_are_no_online_agents": "Accept incoming omnichannel requests even if there are no online agents",

packages/ui-client/src/components/Header/HeaderTag/HeaderTag.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Box, Tag } from '@rocket.chat/fuselage';
22
import type { ComponentProps, FC } from 'react';
33

44
const HeaderTag: FC<ComponentProps<typeof Tag>> = ({ children, ...props }) => (
5-
<Box p={4} withTruncatedText minWidth='x64'>
5+
<Box p={4} withTruncatedText minWidth='x32'>
66
<Tag medium {...props}>
77
{children}
88
</Tag>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { render } from '@testing-library/react';
2+
3+
import HeaderTag from './HeaderTag';
4+
5+
it('should match snapshot', () => {
6+
const { baseElement } = render(<HeaderTag>Test Tag</HeaderTag>);
7+
expect(baseElement).toMatchSnapshot();
8+
});

packages/ui-client/src/components/HeaderV2/HeaderTag/HeaderTag.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type { ComponentProps } from 'react';
44
type HeaderTagProps = ComponentProps<typeof Tag>;
55

66
const HeaderTag = ({ children, ...props }: HeaderTagProps) => (
7-
<Box p={4} withTruncatedText minWidth='x64'>
7+
<Box p={4} withTruncatedText minWidth='x32'>
88
<Tag medium {...props}>
99
{children}
1010
</Tag>
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
2+
3+
exports[`should match snapshot 1`] = `
4+
<body>
5+
<div>
6+
<div
7+
class="rcx-box rcx-box--full rcx-css-1kopyx3"
8+
>
9+
<span
10+
class="rcx-box rcx-box--full rcx-tag rcx-tag--medium"
11+
>
12+
<span
13+
class="rcx-tag__inner"
14+
>
15+
Test Tag
16+
</span>
17+
</span>
18+
</div>
19+
</div>
20+
</body>
21+
`;

0 commit comments

Comments
 (0)