chore: Settings files sanitization (#33057)

pull/32809/head^2
Douglas Fabris 1 year ago committed by GitHub
parent 7e2facc979
commit 5d657eef55
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      apps/meteor/client/omnichannel/priorities/PriorityEditForm.tsx
  2. 26
      apps/meteor/client/views/admin/settings/GroupPage.stories.tsx
  3. 16
      apps/meteor/client/views/admin/settings/GroupSelector.stories.tsx
  4. 43
      apps/meteor/client/views/admin/settings/GroupSelector.tsx
  5. 23
      apps/meteor/client/views/admin/settings/Section.stories.tsx
  6. 59
      apps/meteor/client/views/admin/settings/Setting.stories.tsx
  7. 0
      apps/meteor/client/views/admin/settings/Setting/MemoizedSetting.tsx
  8. 0
      apps/meteor/client/views/admin/settings/Setting/ResetSettingButton/ResetSettingButton.stories.tsx
  9. 0
      apps/meteor/client/views/admin/settings/Setting/ResetSettingButton/ResetSettingButton.tsx
  10. 1
      apps/meteor/client/views/admin/settings/Setting/ResetSettingButton/index.ts
  11. 58
      apps/meteor/client/views/admin/settings/Setting/Setting.stories.tsx
  12. 10
      apps/meteor/client/views/admin/settings/Setting/Setting.tsx
  13. 0
      apps/meteor/client/views/admin/settings/Setting/SettingSkeleton.tsx
  14. 1
      apps/meteor/client/views/admin/settings/Setting/index.ts
  15. 0
      apps/meteor/client/views/admin/settings/Setting/inputs/ActionSettingInput.stories.tsx
  16. 0
      apps/meteor/client/views/admin/settings/Setting/inputs/ActionSettingInput.tsx
  17. 0
      apps/meteor/client/views/admin/settings/Setting/inputs/AssetSettingInput.stories.tsx
  18. 0
      apps/meteor/client/views/admin/settings/Setting/inputs/AssetSettingInput.styles.css
  19. 0
      apps/meteor/client/views/admin/settings/Setting/inputs/AssetSettingInput.tsx
  20. 0
      apps/meteor/client/views/admin/settings/Setting/inputs/BooleanSettingInput.stories.tsx
  21. 0
      apps/meteor/client/views/admin/settings/Setting/inputs/BooleanSettingInput.tsx
  22. 2
      apps/meteor/client/views/admin/settings/Setting/inputs/CodeMirror/CodeMirror.tsx
  23. 0
      apps/meteor/client/views/admin/settings/Setting/inputs/CodeMirror/CodeMirrorBox.tsx
  24. 0
      apps/meteor/client/views/admin/settings/Setting/inputs/CodeMirror/index.ts
  25. 0
      apps/meteor/client/views/admin/settings/Setting/inputs/CodeSettingInput.stories.tsx
  26. 0
      apps/meteor/client/views/admin/settings/Setting/inputs/CodeSettingInput.tsx
  27. 0
      apps/meteor/client/views/admin/settings/Setting/inputs/ColorSettingInput.stories.tsx
  28. 0
      apps/meteor/client/views/admin/settings/Setting/inputs/ColorSettingInput.tsx
  29. 0
      apps/meteor/client/views/admin/settings/Setting/inputs/FontSettingInput.stories.tsx
  30. 0
      apps/meteor/client/views/admin/settings/Setting/inputs/FontSettingInput.tsx
  31. 0
      apps/meteor/client/views/admin/settings/Setting/inputs/GenericSettingInput.stories.tsx
  32. 0
      apps/meteor/client/views/admin/settings/Setting/inputs/GenericSettingInput.tsx
  33. 0
      apps/meteor/client/views/admin/settings/Setting/inputs/IntSettingInput.stories.tsx
  34. 0
      apps/meteor/client/views/admin/settings/Setting/inputs/IntSettingInput.tsx
  35. 0
      apps/meteor/client/views/admin/settings/Setting/inputs/LanguageSettingInput.stories.tsx
  36. 0
      apps/meteor/client/views/admin/settings/Setting/inputs/LanguageSettingInput.tsx
  37. 4
      apps/meteor/client/views/admin/settings/Setting/inputs/LookupSettingInput.tsx
  38. 0
      apps/meteor/client/views/admin/settings/Setting/inputs/MultiSelectSettingInput.stories.tsx
  39. 0
      apps/meteor/client/views/admin/settings/Setting/inputs/MultiSelectSettingInput.tsx
  40. 0
      apps/meteor/client/views/admin/settings/Setting/inputs/PasswordSettingInput.stories.tsx
  41. 0
      apps/meteor/client/views/admin/settings/Setting/inputs/PasswordSettingInput.tsx
  42. 0
      apps/meteor/client/views/admin/settings/Setting/inputs/RelativeUrlSettingInput.stories.tsx
  43. 0
      apps/meteor/client/views/admin/settings/Setting/inputs/RelativeUrlSettingInput.tsx
  44. 2
      apps/meteor/client/views/admin/settings/Setting/inputs/RoomPickSettingInput.tsx
  45. 0
      apps/meteor/client/views/admin/settings/Setting/inputs/SelectSettingInput.stories.tsx
  46. 0
      apps/meteor/client/views/admin/settings/Setting/inputs/SelectSettingInput.tsx
  47. 0
      apps/meteor/client/views/admin/settings/Setting/inputs/SelectTimezoneSettingInput.tsx
  48. 0
      apps/meteor/client/views/admin/settings/Setting/inputs/StringSettingInput.stories.tsx
  49. 0
      apps/meteor/client/views/admin/settings/Setting/inputs/StringSettingInput.tsx
  50. 2
      apps/meteor/client/views/admin/settings/Setting/inputs/TimespanSettingInput.spec.tsx
  51. 2
      apps/meteor/client/views/admin/settings/Setting/inputs/TimespanSettingInput.tsx
  52. 0
      apps/meteor/client/views/admin/settings/Setting/inputs/types.ts
  53. 24
      apps/meteor/client/views/admin/settings/SettingsGroupPage/SettingsGroupPage.stories.tsx
  54. 18
      apps/meteor/client/views/admin/settings/SettingsGroupPage/SettingsGroupPage.tsx
  55. 10
      apps/meteor/client/views/admin/settings/SettingsGroupPage/SettingsGroupPageSkeleton.tsx
  56. 1
      apps/meteor/client/views/admin/settings/SettingsGroupPage/index.ts
  57. 16
      apps/meteor/client/views/admin/settings/SettingsGroupSelector/SettingsGroupSelector.stories.tsx
  58. 42
      apps/meteor/client/views/admin/settings/SettingsGroupSelector/SettingsGroupSelector.tsx
  59. 1
      apps/meteor/client/views/admin/settings/SettingsGroupSelector/index.ts
  60. 4
      apps/meteor/client/views/admin/settings/SettingsRoute.tsx
  61. 21
      apps/meteor/client/views/admin/settings/SettingsSection/SettingsSection.stories.tsx
  62. 24
      apps/meteor/client/views/admin/settings/SettingsSection/SettingsSection.tsx
  63. 8
      apps/meteor/client/views/admin/settings/SettingsSection/SettingsSectionSkeleton.tsx
  64. 1
      apps/meteor/client/views/admin/settings/SettingsSection/index.ts
  65. 26
      apps/meteor/client/views/admin/settings/groups/AssetsGroupPage.tsx
  66. 28
      apps/meteor/client/views/admin/settings/groups/BaseGroupPage.tsx
  67. 35
      apps/meteor/client/views/admin/settings/groups/GenericGroupPage.tsx
  68. 7
      apps/meteor/client/views/admin/settings/groups/LDAPGroupPage.tsx
  69. 2
      apps/meteor/client/views/admin/settings/groups/OAuthGroupPage/CreateOAuthModal.tsx
  70. 20
      apps/meteor/client/views/admin/settings/groups/OAuthGroupPage/OAuthGroupPage.tsx
  71. 1
      apps/meteor/client/views/admin/settings/groups/OAuthGroupPage/index.ts
  72. 49
      apps/meteor/client/views/admin/settings/groups/TabbedGroupPage.tsx
  73. 0
      apps/meteor/client/views/admin/settings/groups/VoipGroupPage/AssignAgentButton.tsx
  74. 0
      apps/meteor/client/views/admin/settings/groups/VoipGroupPage/AssignAgentModal.tsx
  75. 0
      apps/meteor/client/views/admin/settings/groups/VoipGroupPage/RemoveAgentButton.tsx
  76. 0
      apps/meteor/client/views/admin/settings/groups/VoipGroupPage/VoipExtensionsPage.tsx
  77. 20
      apps/meteor/client/views/admin/settings/groups/VoipGroupPage/VoipGroupPage.tsx
  78. 1
      apps/meteor/client/views/admin/settings/groups/VoipGroupPage/index.ts
  79. 2
      apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppSettings/AppSetting.tsx

@ -7,7 +7,7 @@ import type { ReactElement } from 'react';
import React, { useState } from 'react';
import { Controller, useForm } from 'react-hook-form';
import StringSettingInput from '../../views/admin/settings/inputs/StringSettingInput';
import StringSettingInput from '../../views/admin/settings/Setting/inputs/StringSettingInput';
export type PriorityFormData = { name: string; reset: boolean };

@ -1,26 +0,0 @@
import type { ComponentMeta, ComponentStory } from '@storybook/react';
import React from 'react';
import GroupPage from './GroupPage';
export default {
title: 'Admin/Settings/GroupPage',
component: GroupPage,
subcomponents: {
'GroupPage.Skeleton': GroupPage.Skeleton,
},
parameters: {
layout: 'fullscreen',
controls: { hideNoControlsWarning: true },
},
} as ComponentMeta<typeof GroupPage>;
export const Default: ComponentStory<typeof GroupPage> = (args) => <GroupPage {...args} />;
export const WithGroup: ComponentStory<typeof GroupPage> = (args) => <GroupPage {...args} />;
WithGroup.args = {
_id: 'General',
i18nLabel: 'General',
};
export const Skeleton: ComponentStory<typeof GroupPage.Skeleton> = () => <GroupPage.Skeleton />;

@ -1,16 +0,0 @@
import type { ComponentMeta, ComponentStory } from '@storybook/react';
import React from 'react';
import GroupSelector from './GroupSelector';
export default {
title: 'Admin/Settings/GroupSelector',
component: GroupSelector,
parameters: {
layout: 'fullscreen',
controls: { hideNoControlsWarning: true },
},
} as ComponentMeta<typeof GroupSelector>;
export const Default: ComponentStory<typeof GroupSelector> = (args) => <GroupSelector {...args} />;
Default.storyName = 'GroupSelector';

@ -1,43 +0,0 @@
import type { GroupId } from '@rocket.chat/core-typings';
import { useSettingStructure } from '@rocket.chat/ui-contexts';
import React from 'react';
import GroupPage from './GroupPage';
import AssetsGroupPage from './groups/AssetsGroupPage';
import LDAPGroupPage from './groups/LDAPGroupPage';
import OAuthGroupPage from './groups/OAuthGroupPage';
import TabbedGroupPage from './groups/TabbedGroupPage';
import VoipGroupPage from './groups/VoipGroupPage';
type GroupSelectorProps = {
groupId: GroupId;
onClickBack?: () => void;
};
const GroupSelector = ({ groupId, onClickBack }: GroupSelectorProps) => {
const group = useSettingStructure(groupId);
if (!group) {
return <GroupPage.Skeleton />;
}
if (groupId === 'Assets') {
return <AssetsGroupPage {...group} onClickBack={onClickBack} />;
}
if (groupId === 'OAuth') {
return <OAuthGroupPage {...group} onClickBack={onClickBack} />;
}
if (groupId === 'LDAP') {
return <LDAPGroupPage {...group} onClickBack={onClickBack} />;
}
if (groupId === 'Call_Center') {
return <VoipGroupPage {...group} onClickBack={onClickBack} />;
}
return <TabbedGroupPage {...group} onClickBack={onClickBack} />;
};
export default GroupSelector;

@ -1,23 +0,0 @@
import type { ComponentMeta, ComponentStory } from '@storybook/react';
import React from 'react';
import Section from './Section';
export default {
title: 'Admin/Settings/Section',
component: Section,
subcomponents: {
'Section.Skeleton': Section.Skeleton,
},
parameters: {
layout: 'fullscreen',
controls: { hideNoControlsWarning: true },
},
} as ComponentMeta<typeof Section>;
export const Default: ComponentStory<typeof Section> = (args) => <Section {...args} />;
Default.args = {
groupId: 'General',
};
export const Skeleton: ComponentStory<typeof Section.Skeleton> = () => <Section.Skeleton />;

@ -1,59 +0,0 @@
import { FieldGroup } from '@rocket.chat/fuselage';
import type { ComponentMeta, ComponentStory } from '@storybook/react';
import React from 'react';
import Setting from './Setting';
export default {
title: 'Admin/Settings/Setting',
component: Setting,
subcomponents: {
'Setting.Memoized': Setting.Memoized,
},
parameters: {
layout: 'centered',
actions: {
argTypesRegex: '^on.*',
},
},
decorators: [
(fn) => (
<div className='rc-old'>
<div className='page-settings'>{fn()}</div>
</div>
),
],
} as ComponentMeta<typeof Setting>;
export const Default: ComponentStory<typeof Setting.Memoized> = (args) => <Setting.Memoized {...args} />;
Default.args = {
_id: 'setting-id',
label: 'Label',
hint: 'Hint',
};
export const WithCallout: ComponentStory<typeof Setting.Memoized> = (args) => <Setting.Memoized {...args} />;
WithCallout.args = {
_id: 'setting-id',
label: 'Label',
hint: 'Hint',
callout: 'Callout text',
};
export const types = () => (
<FieldGroup>
<Setting.Memoized packageValue _id='setting-id-1' label='Label' type='action' actionText='Action text' />
<Setting.Memoized packageValue='' _id='setting-id-2' label='Label' type='asset' />
<Setting.Memoized packageValue _id='setting-id-3' label='Label' type='boolean' />
<Setting.Memoized packageValue='' _id='setting-id-4' label='Label' type='code' />
<Setting.Memoized packageValue='' _id='setting-id-5' label='Label' type='font' />
<Setting.Memoized packageValue={1} _id='setting-id-6' label='Label' type='int' />
<Setting.Memoized packageValue='' _id='setting-id-7' label='Label' type='language' />
<Setting.Memoized packageValue='' _id='setting-id-8' label='Label' type='password' />
<Setting.Memoized packageValue='' _id='setting-id-9' label='Label' type='relativeUrl' />
<Setting.Memoized packageValue='' _id='setting-id-10' label='Label' type='select' />
<Setting.Memoized packageValue='' _id='setting-id-11' label='Label' type='string' />
</FieldGroup>
);
export const skeleton = () => <Setting.Skeleton />;

@ -0,0 +1 @@
export { default } from './ResetSettingButton';

@ -0,0 +1,58 @@
import { FieldGroup } from '@rocket.chat/fuselage';
import type { ComponentMeta, ComponentStory } from '@storybook/react';
import React from 'react';
import MemoizedSetting from './MemoizedSetting';
import Setting from './Setting';
import SettingSkeleton from './SettingSkeleton';
export default {
title: 'Admin/Settings/Setting',
component: Setting,
parameters: {
layout: 'centered',
actions: {
argTypesRegex: '^on.*',
},
},
decorators: [
(fn) => (
<div className='rc-old'>
<div className='page-settings'>{fn()}</div>
</div>
),
],
} as ComponentMeta<typeof Setting>;
export const Default: ComponentStory<typeof MemoizedSetting> = (args) => <MemoizedSetting {...args} />;
Default.args = {
_id: 'setting-id',
label: 'Label',
hint: 'Hint',
};
export const WithCallout: ComponentStory<typeof MemoizedSetting> = (args) => <MemoizedSetting {...args} />;
WithCallout.args = {
_id: 'setting-id',
label: 'Label',
hint: 'Hint',
callout: 'Callout text',
};
export const types = () => (
<FieldGroup>
<MemoizedSetting packageValue _id='setting-id-1' label='Label' type='action' actionText='Action text' />
<MemoizedSetting packageValue='' _id='setting-id-2' label='Label' type='asset' />
<MemoizedSetting packageValue _id='setting-id-3' label='Label' type='boolean' />
<MemoizedSetting packageValue='' _id='setting-id-4' label='Label' type='code' />
<MemoizedSetting packageValue='' _id='setting-id-5' label='Label' type='font' />
<MemoizedSetting packageValue={1} _id='setting-id-6' label='Label' type='int' />
<MemoizedSetting packageValue='' _id='setting-id-7' label='Label' type='language' />
<MemoizedSetting packageValue='' _id='setting-id-8' label='Label' type='password' />
<MemoizedSetting packageValue='' _id='setting-id-9' label='Label' type='relativeUrl' />
<MemoizedSetting packageValue='' _id='setting-id-10' label='Label' type='select' />
<MemoizedSetting packageValue='' _id='setting-id-11' label='Label' type='string' />
</FieldGroup>
);
export const Skeleton = () => <SettingSkeleton />;

@ -6,10 +6,9 @@ import { useSettingStructure, useTranslation } from '@rocket.chat/ui-contexts';
import type { ReactElement } from 'react';
import React, { useEffect, useMemo, useState, useCallback } from 'react';
import MarkdownText from '../../../components/MarkdownText';
import { useEditableSetting, useEditableSettingsDispatch, useIsEnterprise } from '../EditableSettingsContext';
import MarkdownText from '../../../../components/MarkdownText';
import { useEditableSetting, useEditableSettingsDispatch, useIsEnterprise } from '../../EditableSettingsContext';
import MemoizedSetting from './MemoizedSetting';
import SettingSkeleton from './SettingSkeleton';
type SettingProps = {
className?: string;
@ -165,7 +164,4 @@ function Setting({ className = undefined, settingId, sectionChanged }: SettingPr
);
}
export default Object.assign(Setting, {
Memoized: MemoizedSetting,
Skeleton: SettingSkeleton,
});
export default Setting;

@ -0,0 +1 @@
export { default } from './Setting';

@ -57,7 +57,7 @@ function CodeMirror({
const setupCodeMirror = async (): Promise<void> => {
const CodeMirror = await import('codemirror');
await Promise.all([
import('../../../../../../app/ui/client/lib/codeMirror/codeMirror'),
import('../../../../../../../app/ui/client/lib/codeMirror/codeMirror'),
import('codemirror/addon/edit/matchbrackets'),
import('codemirror/addon/edit/closebrackets'),
import('codemirror/addon/edit/matchtags'),

@ -3,8 +3,8 @@ import type { PathPattern } from '@rocket.chat/rest-typings';
import type { ReactElement } from 'react';
import React from 'react';
import type { AsyncState } from '../../../../hooks/useAsyncState';
import { useEndpointData } from '../../../../hooks/useEndpointData';
import type { AsyncState } from '../../../../../hooks/useAsyncState';
import { useEndpointData } from '../../../../../hooks/useEndpointData';
import ResetSettingButton from '../ResetSettingButton';
import type { SettingInputProps } from './types';

@ -3,7 +3,7 @@ import { Field, FieldLabel, FieldRow } from '@rocket.chat/fuselage';
import type { ReactElement } from 'react';
import React from 'react';
import RoomAutoCompleteMultiple from '../../../../components/RoomAutoCompleteMultiple';
import RoomAutoCompleteMultiple from '../../../../../components/RoomAutoCompleteMultiple';
import ResetSettingButton from '../ResetSettingButton';
import type { SettingInputProps } from './types';

@ -2,7 +2,7 @@ import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { TIMEUNIT } from '../../../../lib/convertTimeUnit';
import { TIMEUNIT } from '../../../../../lib/convertTimeUnit';
import { default as TimespanSettingInput, getHighestTimeUnit } from './TimespanSettingInput';
global.ResizeObserver = jest.fn().mockImplementation(() => ({

@ -3,7 +3,7 @@ import { useTranslation } from '@rocket.chat/ui-contexts';
import type { FormEventHandler, ReactElement } from 'react';
import React, { useMemo, useState } from 'react';
import { TIMEUNIT, timeUnitToMs, msToTimeUnit } from '../../../../lib/convertTimeUnit';
import { TIMEUNIT, timeUnitToMs, msToTimeUnit } from '../../../../../lib/convertTimeUnit';
import ResetSettingButton from '../ResetSettingButton';
import type { SettingInputProps } from './types';

@ -0,0 +1,24 @@
import type { ComponentMeta, ComponentStory } from '@storybook/react';
import React from 'react';
import SettingsGroupPage from './SettingsGroupPage';
import SettingsGroupPageSkeleton from './SettingsGroupPageSkeleton';
export default {
title: 'Admin/Settings/SettingsGroupPage',
component: SettingsGroupPage,
parameters: {
layout: 'fullscreen',
controls: { hideNoControlsWarning: true },
},
} as ComponentMeta<typeof SettingsGroupPage>;
export const Default: ComponentStory<typeof SettingsGroupPage> = (args) => <SettingsGroupPage {...args} />;
export const WithGroup: ComponentStory<typeof SettingsGroupPage> = (args) => <SettingsGroupPage {...args} />;
WithGroup.args = {
_id: 'General',
i18nLabel: 'General',
};
export const Skeleton: ComponentStory<typeof SettingsGroupPageSkeleton> = () => <SettingsGroupPageSkeleton />;

@ -6,12 +6,11 @@ import { useToastMessageDispatch, useSettingsDispatch, useSettings, useTranslati
import type { ReactNode, FormEvent, MouseEvent } from 'react';
import React, { useMemo, memo } from 'react';
import { Page, PageHeader, PageScrollableContentWithShadow, PageFooter } from '../../../components/Page';
import type { EditableSetting } from '../EditableSettingsContext';
import { useEditableSettingsDispatch, useEditableSettings } from '../EditableSettingsContext';
import GroupPageSkeleton from './GroupPageSkeleton';
import { Page, PageHeader, PageScrollableContentWithShadow, PageFooter } from '../../../../components/Page';
import type { EditableSetting } from '../../EditableSettingsContext';
import { useEditableSettingsDispatch, useEditableSettings } from '../../EditableSettingsContext';
type GroupPageProps = {
type SettingsGroupPageProps = {
children: ReactNode;
headerButtons?: ReactNode;
onClickBack?: () => void;
@ -22,7 +21,7 @@ type GroupPageProps = {
isCustom?: boolean;
};
const GroupPage = ({
const SettingsGroupPage = ({
children = undefined,
headerButtons = undefined,
onClickBack,
@ -31,7 +30,7 @@ const GroupPage = ({
i18nDescription = undefined,
tabs = undefined,
isCustom = false,
}: GroupPageProps) => {
}: SettingsGroupPageProps) => {
const t = useTranslation();
const dispatch = useSettingsDispatch();
const dispatchToastMessage = useToastMessageDispatch();
@ -133,7 +132,6 @@ const GroupPage = ({
return <Page>{children}</Page>;
}
// The settings
const isTranslationKey = (key: string): key is TranslationKey => (key as TranslationKey) !== undefined;
return (
@ -178,6 +176,4 @@ const GroupPage = ({
);
};
export default Object.assign(memo(GroupPage), {
Skeleton: GroupPageSkeleton,
});
export default memo(SettingsGroupPage);

@ -1,10 +1,10 @@
import { Accordion, Box, Skeleton } from '@rocket.chat/fuselage';
import React, { useMemo } from 'react';
import { Page, PageHeader, PageContent } from '../../../components/Page';
import Section from './Section';
import { Page, PageHeader, PageContent } from '../../../../components/Page';
import SettingsSectionSkeleton from '../SettingsSection/SettingsSectionSkeleton';
const GroupPageSkeleton = () => (
const SettingsGroupPageSkeleton = () => (
<Page>
<PageHeader title={<Skeleton style={{ width: '20rem' }} />} />
<PageContent>
@ -15,11 +15,11 @@ const GroupPageSkeleton = () => (
<Skeleton width='75%' />
</Box>
<Accordion className='page-settings'>
<Section.Skeleton />
<SettingsSectionSkeleton />
</Accordion>
</Box>
</PageContent>
</Page>
);
export default GroupPageSkeleton;
export default SettingsGroupPageSkeleton;

@ -0,0 +1 @@
export { default } from './SettingsGroupPage';

@ -0,0 +1,16 @@
import type { ComponentMeta, ComponentStory } from '@storybook/react';
import React from 'react';
import SettingsGroupSelector from './SettingsGroupSelector';
export default {
title: 'Admin/Settings/SettingsGroupSelector',
component: SettingsGroupSelector,
parameters: {
layout: 'fullscreen',
controls: { hideNoControlsWarning: true },
},
} as ComponentMeta<typeof SettingsGroupSelector>;
export const Default: ComponentStory<typeof SettingsGroupSelector> = (args) => <SettingsGroupSelector {...args} />;
Default.storyName = 'GroupSelector';

@ -0,0 +1,42 @@
import type { GroupId } from '@rocket.chat/core-typings';
import { useSettingStructure } from '@rocket.chat/ui-contexts';
import React from 'react';
import SettingsGroupPageSkeleton from '../SettingsGroupPage/SettingsGroupPageSkeleton';
import BaseGroupPage from '../groups/BaseGroupPage';
import LDAPGroupPage from '../groups/LDAPGroupPage';
import OAuthGroupPage from '../groups/OAuthGroupPage';
import VoipGroupPage from '../groups/VoipGroupPage';
type SettingsGroupSelectorProps = {
groupId: GroupId;
onClickBack?: () => void;
};
const SettingsGroupSelector = ({ groupId, onClickBack }: SettingsGroupSelectorProps) => {
const group = useSettingStructure(groupId);
if (!group) {
return <SettingsGroupPageSkeleton />;
}
if (groupId === 'OAuth') {
return <OAuthGroupPage {...group} onClickBack={onClickBack} />;
}
if (groupId === 'LDAP') {
return <LDAPGroupPage {...group} onClickBack={onClickBack} />;
}
if (groupId === 'Call_Center') {
return <VoipGroupPage {...group} onClickBack={onClickBack} />;
}
if (groupId === 'Assets') {
return <BaseGroupPage {...group} onClickBack={onClickBack} hasReset={false} />;
}
return <BaseGroupPage {...group} onClickBack={onClickBack} />;
};
export default SettingsGroupSelector;

@ -0,0 +1 @@
export { default } from './SettingsGroupSelector';

@ -4,7 +4,7 @@ import React from 'react';
import NotAuthorizedPage from '../../notAuthorized/NotAuthorizedPage';
import EditableSettingsProvider from './EditableSettingsProvider';
import GroupSelector from './GroupSelector';
import SettingsGroupSelector from './SettingsGroupSelector';
import SettingsPage from './SettingsPage';
export const SettingsRoute = (): ReactElement => {
@ -22,7 +22,7 @@ export const SettingsRoute = (): ReactElement => {
return (
<EditableSettingsProvider>
<GroupSelector groupId={groupId} onClickBack={() => router.navigate('/admin/settings')} />
<SettingsGroupSelector groupId={groupId} onClickBack={() => router.navigate('/admin/settings')} />
</EditableSettingsProvider>
);
};

@ -0,0 +1,21 @@
import type { ComponentMeta, ComponentStory } from '@storybook/react';
import React from 'react';
import SettingsSection from './SettingsSection';
import SettingsSectionSkeleton from './SettingsSectionSkeleton';
export default {
title: 'Admin/Settings/SettingsSection',
component: SettingsSection,
parameters: {
layout: 'fullscreen',
controls: { hideNoControlsWarning: true },
},
} as ComponentMeta<typeof SettingsSection>;
export const Default: ComponentStory<typeof SettingsSection> = (args) => <SettingsSection {...args} />;
Default.args = {
groupId: 'General',
};
export const Skeleton: ComponentStory<typeof SettingsSectionSkeleton> = () => <SettingsSectionSkeleton />;

@ -6,29 +6,30 @@ import { useTranslation } from '@rocket.chat/ui-contexts';
import type { ReactElement, ReactNode } from 'react';
import React, { useMemo } from 'react';
import { useEditableSettings, useEditableSettingsDispatch } from '../EditableSettingsContext';
import SectionSkeleton from './SectionSkeleton';
import Setting from './Setting';
import { useEditableSettings, useEditableSettingsDispatch } from '../../EditableSettingsContext';
import Setting from '../Setting';
type SectionProps = {
type SettingsSectionProps = {
groupId: string;
hasReset?: boolean;
sectionName: string;
tabName?: string;
currentTab?: string;
solo: boolean;
help?: ReactNode;
children?: ReactNode;
};
function Section({ groupId, hasReset = true, sectionName, tabName = '', solo, help, children }: SectionProps): ReactElement {
function SettingsSection({ groupId, hasReset = true, sectionName, currentTab, solo, help, children }: SettingsSectionProps): ReactElement {
const t = useTranslation();
const editableSettings = useEditableSettings(
useMemo(
() => ({
group: groupId,
section: sectionName,
tab: tabName,
tab: currentTab,
}),
[groupId, sectionName, tabName],
[groupId, sectionName, currentTab],
),
);
@ -65,8 +66,6 @@ function Section({ groupId, hasReset = true, sectionName, tabName = '', solo, he
);
});
const t = useTranslation();
const handleResetSectionClick = (): void => {
reset();
};
@ -82,7 +81,6 @@ function Section({ groupId, hasReset = true, sectionName, tabName = '', solo, he
{help}
</Box>
)}
<FieldGroup>
{editableSettings.map(
(setting) => isSetting(setting) && <Setting key={setting._id} settingId={setting._id} sectionChanged={changed} />,
@ -104,6 +102,4 @@ function Section({ groupId, hasReset = true, sectionName, tabName = '', solo, he
);
}
export default Object.assign(Section, {
Skeleton: SectionSkeleton,
});
export default SettingsSection;

@ -2,9 +2,9 @@ import { Accordion, Box, FieldGroup, Skeleton } from '@rocket.chat/fuselage';
import type { ReactElement } from 'react';
import React from 'react';
import Setting from './Setting';
import SettingSkeleton from '../Setting/SettingSkeleton';
function SectionSkeleton(): ReactElement {
function SettingsSectionSkeleton(): ReactElement {
return (
<Accordion.Item noncollapsible title={<Skeleton />}>
<Box is='p' color='hint' fontScale='p2'>
@ -13,11 +13,11 @@ function SectionSkeleton(): ReactElement {
<FieldGroup>
{Array.from({ length: 10 }).map((_, i) => (
<Setting.Skeleton key={i} />
<SettingSkeleton key={i} />
))}
</FieldGroup>
</Accordion.Item>
);
}
export default SectionSkeleton;
export default SettingsSectionSkeleton;

@ -0,0 +1 @@
export { default } from './SettingsSection';

@ -1,26 +0,0 @@
import type { ISetting } from '@rocket.chat/core-typings';
import type { ReactElement } from 'react';
import React, { memo } from 'react';
import { useEditableSettingsGroupSections } from '../../EditableSettingsContext';
import GroupPage from '../GroupPage';
import Section from '../Section';
type AssetsGroupPageProps = ISetting & {
onClickBack?: () => void;
};
function AssetsGroupPage({ _id, onClickBack, ...group }: AssetsGroupPageProps): ReactElement {
const sections = useEditableSettingsGroupSections(_id);
const solo = sections.length === 1;
return (
<GroupPage _id={_id} onClickBack={onClickBack} {...group}>
{sections.map((sectionName) => (
<Section key={sectionName} groupId={_id} hasReset={false} sectionName={sectionName} solo={solo} />
))}
</GroupPage>
);
}
export default memo(AssetsGroupPage);

@ -0,0 +1,28 @@
import type { ReactElement } from 'react';
import React from 'react';
import { useEditableSettingsGroupSections, useEditableSettingsGroupTabs } from '../../EditableSettingsContext';
import GenericGroupPage from './GenericGroupPage';
import TabbedGroupPage from './TabbedGroupPage';
type BaseGroupPageProps = {
_id: string;
i18nLabel: string;
headerButtons?: ReactElement;
hasReset?: boolean;
onClickBack?: () => void;
};
const BaseGroupPage = ({ _id, i18nLabel, headerButtons, hasReset, onClickBack, ...props }: BaseGroupPageProps) => {
const tabs = useEditableSettingsGroupTabs(_id);
const sections = useEditableSettingsGroupSections(_id);
if (tabs.length > 1) {
return (
<TabbedGroupPage _id={_id} i18nLabel={i18nLabel} headerButtons={headerButtons} tabs={tabs} onClickBack={onClickBack} {...props} />
);
}
return <GenericGroupPage _id={_id} i18nLabel={i18nLabel} sections={sections} onClickBack={onClickBack} hasReset={hasReset} {...props} />;
};
export default BaseGroupPage;

@ -1,25 +1,38 @@
import type { ISetting } from '@rocket.chat/core-typings';
import type { ReactElement } from 'react';
import type { ReactElement, ReactNode } from 'react';
import React, { memo } from 'react';
import { useEditableSettingsGroupSections } from '../../EditableSettingsContext';
import GroupPage from '../GroupPage';
import Section from '../Section';
import SettingsGroupPage from '../SettingsGroupPage';
import Section from '../SettingsSection';
type GenericGroupPageProps = ISetting & {
type GenericGroupPageProps = {
_id: string;
i18nLabel: string;
tabs?: ReactNode;
currentTab?: string;
hasReset?: boolean;
sections: string[];
headerButtons?: ReactNode;
onClickBack?: () => void;
};
function GenericGroupPage({ _id, onClickBack, ...props }: GenericGroupPageProps): ReactElement {
const sections = useEditableSettingsGroupSections(_id);
function GenericGroupPage({
_id,
i18nLabel,
sections,
tabs,
currentTab,
hasReset,
onClickBack,
...props
}: GenericGroupPageProps): ReactElement {
const solo = sections.length === 1;
return (
<GroupPage _id={_id} onClickBack={onClickBack} {...props}>
<SettingsGroupPage _id={_id} i18nLabel={i18nLabel} onClickBack={onClickBack} tabs={tabs} {...props}>
{sections.map((sectionName) => (
<Section key={sectionName || ''} groupId={_id} sectionName={sectionName} solo={solo} />
<Section key={sectionName || ''} hasReset={hasReset} groupId={_id} sectionName={sectionName} currentTab={currentTab} solo={solo} />
))}
</GroupPage>
</SettingsGroupPage>
);
}

@ -8,13 +8,13 @@ import React, { memo, useMemo } from 'react';
import GenericModal from '../../../../components/GenericModal';
import { useExternalLink } from '../../../../hooks/useExternalLink';
import { useEditableSettings } from '../../EditableSettingsContext';
import TabbedGroupPage from './TabbedGroupPage';
import BaseGroupPage from './BaseGroupPage';
type LDAPGroupPageProps = ISetting & {
onClickBack?: () => void;
};
function LDAPGroupPage({ _id, onClickBack, ...group }: LDAPGroupPageProps) {
function LDAPGroupPage({ _id, i18nLabel, onClickBack, ...group }: LDAPGroupPageProps) {
const t = useTranslation();
const dispatchToastMessage = useToastMessageDispatch();
const testConnection = useEndpoint('POST', '/v1/ldap.testConnection');
@ -129,8 +129,9 @@ function LDAPGroupPage({ _id, onClickBack, ...group }: LDAPGroupPageProps) {
};
return (
<TabbedGroupPage
<BaseGroupPage
_id={_id}
i18nLabel={i18nLabel}
onClickBack={onClickBack}
{...group}
headerButtons={

@ -3,7 +3,7 @@ import { useTranslation } from '@rocket.chat/ui-contexts';
import type { ReactElement, FormEvent, SyntheticEvent } from 'react';
import React, { useState } from 'react';
import GenericModal from '../../../../components/GenericModal';
import GenericModal from '../../../../../components/GenericModal';
type CreateOAuthModalProps = {
onConfirm: (text: string) => Promise<void>;

@ -5,11 +5,11 @@ import { useToastMessageDispatch, useAbsoluteUrl, useMethod, useTranslation, use
import type { ReactElement } from 'react';
import React, { memo, useEffect, useState } from 'react';
import { strRight } from '../../../../../lib/utils/stringUtils';
import GenericModal from '../../../../components/GenericModal';
import { useEditableSettingsGroupSections } from '../../EditableSettingsContext';
import GroupPage from '../GroupPage';
import Section from '../Section';
import { strRight } from '../../../../../../lib/utils/stringUtils';
import GenericModal from '../../../../../components/GenericModal';
import { useEditableSettingsGroupSections } from '../../../EditableSettingsContext';
import SettingsGroupPage from '../../SettingsGroupPage';
import SettingsSection from '../../SettingsSection';
import CreateOAuthModal from './CreateOAuthModal';
type OAuthGroupPageProps = ISetting & {
@ -94,7 +94,7 @@ function OAuthGroupPage({ _id, onClickBack, ...group }: OAuthGroupPageProps): Re
};
return (
<GroupPage
<SettingsGroupPage
_id={_id}
{...group}
onClickBack={onClickBack}
@ -112,7 +112,7 @@ function OAuthGroupPage({ _id, onClickBack, ...group }: OAuthGroupPageProps): Re
const handleRemoveCustomOAuthButtonClick = removeCustomOauthFactory(id);
return (
<Section
<SettingsSection
key={sectionName}
groupId={_id}
help={
@ -130,13 +130,13 @@ function OAuthGroupPage({ _id, onClickBack, ...group }: OAuthGroupPageProps): Re
{t('Remove_custom_oauth')}
</Button>
</div>
</Section>
</SettingsSection>
);
}
return <Section key={sectionName} groupId={_id} sectionName={sectionName} solo={solo} />;
return <SettingsSection key={sectionName} groupId={_id} sectionName={sectionName} solo={solo} />;
})}
</GroupPage>
</SettingsGroupPage>
);
}

@ -0,0 +1 @@
export { default } from './OAuthGroupPage';

@ -1,54 +1,47 @@
import type { ISetting } from '@rocket.chat/core-typings';
import { Tabs } from '@rocket.chat/fuselage';
import { Tabs, TabsItem } from '@rocket.chat/fuselage';
import type { TranslationKey } from '@rocket.chat/ui-contexts';
import { useTranslation } from '@rocket.chat/ui-contexts';
import type { ReactElement } from 'react';
import React, { memo, useState, useMemo } from 'react';
import { useEditableSettingsGroupSections, useEditableSettingsGroupTabs } from '../../EditableSettingsContext';
import GroupPage from '../GroupPage';
import Section from '../Section';
import { useEditableSettingsGroupSections } from '../../EditableSettingsContext';
import GenericGroupPage from './GenericGroupPage';
type TabbedGroupPageProps = ISetting & {
type TabbedGroupPageProps = {
headerButtons?: ReactElement;
_id: string;
i18nLabel: string;
tabs: string[];
onClickBack?: () => void;
};
function TabbedGroupPage({ _id, onClickBack, ...props }: TabbedGroupPageProps): JSX.Element {
function TabbedGroupPage({ _id, tabs, i18nLabel, onClickBack, ...props }: TabbedGroupPageProps) {
const t = useTranslation();
const tabs = useEditableSettingsGroupTabs(_id);
const [tab, setTab] = useState(tabs[0]);
const handleTabClick = useMemo(() => (tab: string) => (): void => setTab(tab), [setTab]);
const sections = useEditableSettingsGroupSections(_id, tab);
const solo = sections.length === 1;
if (!tabs.length || (tabs.length === 1 && !tabs[0])) {
return <GenericGroupPage _id={_id} onClickBack={onClickBack} {...props} />;
}
if (!tab && tabs[0]) {
setTab(tabs[0]);
}
const [currentTab, setCurrentTab] = useState(tabs[0]);
const handleTabClick = useMemo(() => (tab: string) => (): void => setCurrentTab(tab), [setCurrentTab]);
const sections = useEditableSettingsGroupSections(_id, currentTab);
const tabsComponent = (
<Tabs>
{tabs.map((tabName) => (
<Tabs.Item key={tabName || ''} selected={tab === tabName} onClick={handleTabClick(tabName)}>
<TabsItem key={tabName || ''} selected={currentTab === tabName} onClick={handleTabClick(tabName)}>
{tabName ? t(tabName as TranslationKey) : t(_id as TranslationKey)}
</Tabs.Item>
</TabsItem>
))}
</Tabs>
);
return (
<GroupPage _id={_id} onClickBack={onClickBack} {...props} tabs={tabsComponent}>
{sections.map((sectionName) => (
<Section key={sectionName || ''} groupId={_id} sectionName={sectionName} tabName={tab} solo={solo} />
))}
</GroupPage>
<GenericGroupPage
_id={_id}
i18nLabel={i18nLabel}
onClickBack={onClickBack}
sections={sections}
currentTab={currentTab}
tabs={tabsComponent}
{...props}
/>
);
}

@ -4,12 +4,12 @@ import type { TranslationKey } from '@rocket.chat/ui-contexts';
import { useSetting, useTranslation } from '@rocket.chat/ui-contexts';
import React, { memo, useMemo, useState } from 'react';
import GenericNoResults from '../../../../components/GenericNoResults';
import { PageScrollableContentWithShadow } from '../../../../components/Page';
import { useEditableSettingsGroupSections } from '../../EditableSettingsContext';
import GroupPage from '../GroupPage';
import Section from '../Section';
import VoipExtensionsPage from './voip/VoipExtensionsPage';
import GenericNoResults from '../../../../../components/GenericNoResults';
import { PageScrollableContentWithShadow } from '../../../../../components/Page';
import { useEditableSettingsGroupSections } from '../../../EditableSettingsContext';
import SettingsGroupPage from '../../SettingsGroupPage';
import SettingsSection from '../../SettingsSection';
import VoipExtensionsPage from './VoipExtensionsPage';
type VoipGroupPageProps = ISetting & {
onClickBack?: () => void;
@ -44,13 +44,13 @@ function VoipGroupPage({ _id, onClickBack, ...group }: VoipGroupPageProps) {
voipEnabled ? (
<VoipExtensionsPage />
) : (
<GenericNoResults icon='warning' title={t('Voip_is_disabled')} description={t('Voip_is_disabled_description')}></GenericNoResults>
<GenericNoResults icon='warning' title={t('Voip_is_disabled')} description={t('Voip_is_disabled_description')} />
),
[t, voipEnabled],
);
return (
<GroupPage _id={_id} {...group} tabs={tabsComponent} isCustom={true} onClickBack={onClickBack}>
<SettingsGroupPage _id={_id} {...group} tabs={tabsComponent} isCustom={true} onClickBack={onClickBack}>
{tab === 'Extensions' ? (
ExtensionsPageComponent
) : (
@ -58,13 +58,13 @@ function VoipGroupPage({ _id, onClickBack, ...group }: VoipGroupPageProps) {
<Box marginBlock='none' marginInline='auto' width='full' maxWidth='x580'>
<Accordion className='page-settings'>
{sections.map((sectionName) => (
<Section key={sectionName || ''} groupId={_id} sectionName={sectionName} tabName={tab} solo={false} />
<SettingsSection key={sectionName || ''} groupId={_id} sectionName={sectionName} currentTab={tab} solo={false} />
))}
</Accordion>
</Box>
</PageScrollableContentWithShadow>
)}
</GroupPage>
</SettingsGroupPage>
);
}

@ -0,0 +1 @@
export { default } from './VoipGroupPage';

@ -7,7 +7,7 @@ import { Controller, useFormContext } from 'react-hook-form';
import { Utilities } from '../../../../../../ee/lib/misc/Utilities';
import MarkdownText from '../../../../../components/MarkdownText';
import MemoizedSetting from '../../../../admin/settings/MemoizedSetting';
import MemoizedSetting from '../../../../admin/settings/Setting/MemoizedSetting';
type AppTranslationFunction = {
(key: string, ...replaces: unknown[]): string;

Loading…
Cancel
Save