Skip to content

Commit 4c2f04f

Browse files
chore: Show ldap attribute sync settings on abac page (#40088)
Co-authored-by: Aleksander Nicacio da Silva <aleksander.silva@rocket.chat>
1 parent 448754d commit 4c2f04f

6 files changed

Lines changed: 100 additions & 57 deletions

File tree

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { useStableCallback } from '@rocket.chat/fuselage-hooks';
2+
import { GenericModal } from '@rocket.chat/ui-client';
3+
import type { TranslationKey } from '@rocket.chat/ui-contexts';
4+
import { useSetModal, useToastMessageDispatch, useEndpoint } from '@rocket.chat/ui-contexts';
5+
import { useTranslation } from 'react-i18next';
6+
7+
export const useLdapSync = () => {
8+
const { t } = useTranslation();
9+
const dispatchToastMessage = useToastMessageDispatch();
10+
const setModal = useSetModal();
11+
const testConnection = useEndpoint('POST', '/v1/ldap.testConnection');
12+
const syncNow = useEndpoint('POST', '/v1/ldap.syncNow');
13+
const closeModal = useStableCallback(() => setModal(null));
14+
15+
const handleSyncNow = async (): Promise<void> => {
16+
closeModal();
17+
18+
try {
19+
const { message } = await syncNow();
20+
dispatchToastMessage({ type: 'success', message: t(message as TranslationKey) });
21+
} catch (error) {
22+
dispatchToastMessage({ type: 'error', message: error });
23+
}
24+
};
25+
26+
return async (): Promise<void> => {
27+
try {
28+
await testConnection();
29+
} catch {
30+
dispatchToastMessage({ type: 'error', message: t('Connection_failed') });
31+
return;
32+
}
33+
34+
setModal(
35+
<GenericModal
36+
variant='info'
37+
confirmText={t('Sync')}
38+
cancelText={t('Cancel')}
39+
title={t('Execute_Synchronization_Now')}
40+
onConfirm={handleSyncNow}
41+
onClose={closeModal}
42+
>
43+
{t('LDAP_Sync_Now_Description')}
44+
</GenericModal>,
45+
);
46+
};
47+
};

apps/meteor/client/views/admin/ABAC/ABACSettingTab/AbacEnabledToggle.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@ import SettingSkeleton from '../../settings/Setting/SettingSkeleton';
1111

1212
type ABACEnabledToggleProps = {
1313
hasABAC: 'loading' | boolean;
14+
className?: string;
1415
};
1516

16-
const ABACEnabledToggle = ({ hasABAC }: ABACEnabledToggleProps) => {
17+
const ABACEnabledToggle = ({ className, hasABAC }: ABACEnabledToggleProps) => {
1718
const setting = useEditableSetting('ABAC_Enabled');
1819
const setModal = useSetModal();
1920
const dispatch = useSettingsDispatch();
@@ -89,6 +90,7 @@ const ABACEnabledToggle = ({ hasABAC }: ABACEnabledToggleProps) => {
8990
hasResetButton={hasABAC && setting.packageValue !== setting.value}
9091
onChangeValue={(value: SettingValue) => onChange(value === true)}
9192
onResetButtonClick={() => onReset()}
93+
className={className}
9294
/>
9395
);
9496
};

apps/meteor/client/views/admin/ABAC/ABACSettingTab/SettingsPage.tsx

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,40 @@
1-
import { Box, Callout, Margins } from '@rocket.chat/fuselage';
2-
import { Trans } from 'react-i18next';
1+
import { Accordion, AccordionItem, Box, Callout, FieldGroup } from '@rocket.chat/fuselage';
2+
import { useTranslation, Trans } from 'react-i18next';
33

44
import AbacEnabledToggle from './AbacEnabledToggle';
55
import SettingField from './SettingField';
66
import { useHasLicenseModule } from '../../../../hooks/useHasLicenseModule';
77
import { links } from '../../../../lib/links';
88

99
const SettingsPage = () => {
10+
const { t } = useTranslation();
1011
const { data: hasABAC = false } = useHasLicenseModule('abac');
1112
return (
12-
<Box maxWidth='x600' w='full' alignSelf='center'>
13-
<Box>
14-
<Margins block={24}>
15-
<AbacEnabledToggle hasABAC={hasABAC} />
16-
<SettingField settingId='ABAC_ShowAttributesInRooms' />
17-
<SettingField settingId='Abac_Cache_Decision_Time_Seconds' />
13+
<Box maxWidth='x600' w='full' alignSelf='center' overflow='auto' mb={24}>
14+
<FieldGroup>
15+
<AbacEnabledToggle hasABAC={hasABAC} />
16+
<SettingField settingId='ABAC_ShowAttributesInRooms' />
17+
<SettingField settingId='Abac_Cache_Decision_Time_Seconds' />
1818

19-
<Callout>
20-
<Trans i18nKey='ABAC_Enabled_callout'>
21-
User attributes are synchronized via LDAP
22-
<a href={links.go.abacLDAPDocs} rel='noopener noreferrer' target='_blank'>
23-
Learn more
24-
</a>
25-
</Trans>
26-
</Callout>
27-
</Margins>
28-
</Box>
19+
<Accordion>
20+
<AccordionItem title={t('LDAP_DataSync_ABAC')}>
21+
<FieldGroup>
22+
<SettingField settingId='LDAP_Background_Sync_ABAC_Attributes' />
23+
<SettingField settingId='LDAP_Background_Sync_ABAC_Attributes_Interval' />
24+
<SettingField settingId='LDAP_ABAC_AttributeMap' />
25+
</FieldGroup>
26+
</AccordionItem>
27+
</Accordion>
28+
29+
<Callout>
30+
<Trans i18nKey='ABAC_Enabled_callout'>
31+
User attributes are synchronized via LDAP
32+
<a href={links.go.abacLDAPDocs} rel='noopener noreferrer' target='_blank'>
33+
Learn more
34+
</a>
35+
</Trans>
36+
</Callout>
37+
</FieldGroup>
2938
</Box>
3039
);
3140
};

apps/meteor/client/views/admin/ABAC/AdminABACPage.tsx

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { Box, Button, Callout } from '@rocket.chat/fuselage';
1+
import { Box, Button, ButtonGroup, Callout } from '@rocket.chat/fuselage';
22
import { useEffectEvent } from '@rocket.chat/fuselage-hooks';
33
import { ContextualbarDialog, Page, PageContent, PageHeader } from '@rocket.chat/ui-client';
4-
import { useRouteParameter, useRouter } from '@rocket.chat/ui-contexts';
4+
import { useSetting, useRouteParameter, useRouter } from '@rocket.chat/ui-contexts';
55
import { Trans, useTranslation } from 'react-i18next';
66

77
import AttributesContextualBar from './ABACAttributesTab/AttributesContextualBar';
@@ -15,6 +15,7 @@ import SettingsPage from './ABACSettingTab/SettingsPage';
1515
import AdminABACTabs from './AdminABACTabs';
1616
import { useIsABACAvailable } from './hooks/useIsABACAvailable';
1717
import { useExternalLink } from '../../../hooks/useExternalLink';
18+
import { useLdapSync } from '../../../hooks/useLdapSync';
1819
import { links } from '../../../lib/links';
1920

2021
type AdminABACPageProps = {
@@ -29,6 +30,10 @@ const AdminABACPage = ({ shouldShowWarning }: AdminABACPageProps) => {
2930
const context = useRouteParameter('context');
3031
const learnMore = useExternalLink();
3132
const isABACAvailable = useIsABACAvailable();
33+
const ldapEnabled = useSetting('LDAP_Enable');
34+
const abacEnabled = useSetting('ABAC_Enabled');
35+
const handleSyncNow = useLdapSync();
36+
const isSyncDisabled = !ldapEnabled || !abacEnabled;
3237

3338
const handleCloseContextualbar = useEffectEvent((): void => {
3439
if (!context) {
@@ -48,9 +53,18 @@ const AdminABACPage = ({ shouldShowWarning }: AdminABACPageProps) => {
4853
<Page flexDirection='row'>
4954
<Page>
5055
<PageHeader title={t('ABAC')}>
51-
<Button icon='new-window' secondary onClick={() => learnMore(links.go.abacDocs)}>
52-
{t('ABAC_Learn_More')}
53-
</Button>
56+
<ButtonGroup>
57+
<Button
58+
disabled={isSyncDisabled}
59+
title={isSyncDisabled ? t('Enable_ABAC_and_LDAP_to_sync') : undefined}
60+
onClick={handleSyncNow}
61+
>
62+
{t('LDAP_Sync_Now')}
63+
</Button>
64+
<Button icon='new-window' secondary onClick={() => learnMore(links.go.abacDocs)}>
65+
{t('ABAC_Learn_More')}
66+
</Button>
67+
</ButtonGroup>
5468
</PageHeader>
5569
{shouldShowWarning && (
5670
<Box mi={24} mb={16}>

apps/meteor/client/views/admin/settings/groups/LDAPGroupPage.tsx

Lines changed: 3 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { useTranslation } from 'react-i18next';
99

1010
import BaseGroupPage from './BaseGroupPage';
1111
import { useExternalLink } from '../../../../hooks/useExternalLink';
12+
import { useLdapSync } from '../../../../hooks/useLdapSync';
1213
import { links } from '../../../../lib/links';
1314
import { useEditableSettings } from '../../EditableSettingsContext';
1415

@@ -20,11 +21,11 @@ function LDAPGroupPage({ _id, i18nLabel, onClickBack, ...group }: LDAPGroupPageP
2021
const { t } = useTranslation();
2122
const dispatchToastMessage = useToastMessageDispatch();
2223
const testConnection = useEndpoint('POST', '/v1/ldap.testConnection');
23-
const syncNow = useEndpoint('POST', '/v1/ldap.syncNow');
2424
const testSearch = useEndpoint('POST', '/v1/ldap.testSearch');
2525
const ldapEnabled = useSetting('LDAP_Enable');
2626
const setModal = useSetModal();
2727
const closeModal = useEffectEvent(() => setModal());
28+
const handleSyncNow = useLdapSync();
2829

2930
const handleLinkClick = useExternalLink();
3031

@@ -48,37 +49,6 @@ function LDAPGroupPage({ _id, i18nLabel, onClickBack, ...group }: LDAPGroupPageP
4849
}
4950
};
5051

51-
const handleSyncNowButtonClick = async (): Promise<void> => {
52-
try {
53-
await testConnection();
54-
const confirmSync = async (): Promise<void> => {
55-
closeModal();
56-
57-
try {
58-
const { message } = await syncNow();
59-
dispatchToastMessage({ type: 'success', message: t(message as Parameters<typeof t>[0]) });
60-
} catch (error) {
61-
error instanceof Error && dispatchToastMessage({ type: 'error', message: error });
62-
}
63-
};
64-
65-
setModal(
66-
<GenericModal
67-
variant='info'
68-
confirmText={t('Sync')}
69-
cancelText={t('Cancel')}
70-
title={t('Execute_Synchronization_Now')}
71-
onConfirm={confirmSync}
72-
onClose={closeModal}
73-
>
74-
{t('LDAP_Sync_Now_Description')}
75-
</GenericModal>,
76-
);
77-
} catch (error) {
78-
error instanceof Error && dispatchToastMessage({ type: 'error', message: error });
79-
}
80-
};
81-
8252
const handleSearchTestButtonClick = async (): Promise<void> => {
8353
try {
8454
await testConnection();
@@ -144,7 +114,7 @@ function LDAPGroupPage({ _id, i18nLabel, onClickBack, ...group }: LDAPGroupPageP
144114
<Button disabled={!ldapEnabled || changed} onClick={handleSearchTestButtonClick}>
145115
{t('Test_LDAP_Search')}
146116
</Button>
147-
<Button disabled={!ldapEnabled || changed} onClick={handleSyncNowButtonClick}>
117+
<Button disabled={!ldapEnabled || changed} onClick={handleSyncNow}>
148118
{t('LDAP_Sync_Now')}
149119
</Button>
150120
<Button role='link' onClick={() => handleLinkClick(links.go.ldapDocs)}>

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
"ABAC_Room_Attributes": "Room Attributes",
8585
"ABAC_Logs": "Logs",
8686
"ABAC_Invalid_attribute": "Invalid characters in attribute name or values",
87+
"Enable_ABAC_and_LDAP_to_sync": "Enable ABAC and LDAP to be able to sync",
8788
"AI_Actions": "AI actions",
8889
"API": "API",
8990
"API_Add_Personal_Access_Token": "Add new Personal Access Token",

0 commit comments

Comments
 (0)