{value?.url ? (
-
+
>
);
}
diff --git a/apps/meteor/client/views/admin/settings/inputs/BooleanSettingInput.tsx b/apps/meteor/client/views/admin/settings/inputs/BooleanSettingInput.tsx
index acac16b5b7e8..308e781e8e46 100644
--- a/apps/meteor/client/views/admin/settings/inputs/BooleanSettingInput.tsx
+++ b/apps/meteor/client/views/admin/settings/inputs/BooleanSettingInput.tsx
@@ -1,4 +1,4 @@
-import { Field, ToggleSwitch } from '@rocket.chat/fuselage';
+import { FieldLabel, FieldRow, ToggleSwitch } from '@rocket.chat/fuselage';
import type { ReactElement, SyntheticEvent } from 'react';
import React from 'react';
@@ -30,7 +30,7 @@ function BooleanSettingInput({
};
return (
-
+
-
+
{label}
-
+
{hasResetButton && }
-
+
);
}
diff --git a/apps/meteor/client/views/admin/settings/inputs/CodeSettingInput.tsx b/apps/meteor/client/views/admin/settings/inputs/CodeSettingInput.tsx
index 2b615a63b8d5..85698b66e2b7 100644
--- a/apps/meteor/client/views/admin/settings/inputs/CodeSettingInput.tsx
+++ b/apps/meteor/client/views/admin/settings/inputs/CodeSettingInput.tsx
@@ -1,4 +1,4 @@
-import { Box, Field, Flex } from '@rocket.chat/fuselage';
+import { Box, FieldLabel, FieldHint, Flex } from '@rocket.chat/fuselage';
import type { ReactElement } from 'react';
import React from 'react';
@@ -43,12 +43,12 @@ function CodeSettingInput({
<>
-
+
{label}
-
+
{hasResetButton && }
- {hint && {hint}}
+ {hint && {hint}}
-
+
{label}
-
+
{hasResetButton && }
-
+
{editor === 'color' && (
@@ -104,9 +104,9 @@ function ColorSettingInput({
options={allowedTypes.map((type) => [type, t(type)])}
/>
-
+
- Variable name: {_id.replace(/theme-color-/, '@')}
+ Variable name: {_id.replace(/theme-color-/, '@')}
>
);
}
diff --git a/apps/meteor/client/views/admin/settings/inputs/FontSettingInput.tsx b/apps/meteor/client/views/admin/settings/inputs/FontSettingInput.tsx
index 2d7a93b9c96f..35b255b4e756 100644
--- a/apps/meteor/client/views/admin/settings/inputs/FontSettingInput.tsx
+++ b/apps/meteor/client/views/admin/settings/inputs/FontSettingInput.tsx
@@ -1,4 +1,4 @@
-import { Box, Field, Flex, TextInput } from '@rocket.chat/fuselage';
+import { Box, FieldLabel, FieldRow, Flex, TextInput } from '@rocket.chat/fuselage';
import type { FormEventHandler, ReactElement } from 'react';
import React from 'react';
@@ -36,13 +36,13 @@ function FontSettingInput({
<>
-
+
{label}
-
+
{hasResetButton && }
-
+
-
+
>
);
}
diff --git a/apps/meteor/client/views/admin/settings/inputs/GenericSettingInput.tsx b/apps/meteor/client/views/admin/settings/inputs/GenericSettingInput.tsx
index 46ffc61a8f3b..32425a57c698 100644
--- a/apps/meteor/client/views/admin/settings/inputs/GenericSettingInput.tsx
+++ b/apps/meteor/client/views/admin/settings/inputs/GenericSettingInput.tsx
@@ -1,4 +1,4 @@
-import { Box, Field, Flex, TextInput } from '@rocket.chat/fuselage';
+import { Box, FieldLabel, FieldRow, Flex, TextInput } from '@rocket.chat/fuselage';
import type { FormEventHandler, ReactElement } from 'react';
import React from 'react';
@@ -36,13 +36,13 @@ function GenericSettingInput({
<>
-
+
{label}
-
+
{hasResetButton && }
-
+
-
+
>
);
}
diff --git a/apps/meteor/client/views/admin/settings/inputs/IntSettingInput.tsx b/apps/meteor/client/views/admin/settings/inputs/IntSettingInput.tsx
index 03f837117223..cd5abd54f481 100644
--- a/apps/meteor/client/views/admin/settings/inputs/IntSettingInput.tsx
+++ b/apps/meteor/client/views/admin/settings/inputs/IntSettingInput.tsx
@@ -1,4 +1,4 @@
-import { Box, Field, Flex, InputBox } from '@rocket.chat/fuselage';
+import { Box, FieldLabel, FieldRow, Flex, InputBox } from '@rocket.chat/fuselage';
import type { FormEventHandler, ReactElement } from 'react';
import React from 'react';
@@ -37,13 +37,13 @@ function IntSettingInput({
<>
-
+
{label}
-
+
{hasResetButton && }
-
+
-
+
>
);
}
diff --git a/apps/meteor/client/views/admin/settings/inputs/LanguageSettingInput.tsx b/apps/meteor/client/views/admin/settings/inputs/LanguageSettingInput.tsx
index 770edd5c12a6..8bfe977aaf39 100644
--- a/apps/meteor/client/views/admin/settings/inputs/LanguageSettingInput.tsx
+++ b/apps/meteor/client/views/admin/settings/inputs/LanguageSettingInput.tsx
@@ -1,4 +1,4 @@
-import { Box, Field, Flex, Select } from '@rocket.chat/fuselage';
+import { Box, FieldLabel, FieldRow, Flex, Select } from '@rocket.chat/fuselage';
import { useLanguages } from '@rocket.chat/ui-contexts';
import type { ReactElement } from 'react';
import React from 'react';
@@ -40,13 +40,13 @@ function LanguageSettingInput({
<>
-
+
{label}
-
+
{hasResetButton && }
-
+
+
>
);
}
diff --git a/apps/meteor/client/views/admin/settings/inputs/LookupSettingInput.tsx b/apps/meteor/client/views/admin/settings/inputs/LookupSettingInput.tsx
index 8b7175320d98..15a1aab443d7 100644
--- a/apps/meteor/client/views/admin/settings/inputs/LookupSettingInput.tsx
+++ b/apps/meteor/client/views/admin/settings/inputs/LookupSettingInput.tsx
@@ -1,4 +1,4 @@
-import { Box, Field, Flex, Select } from '@rocket.chat/fuselage';
+import { Box, FieldLabel, FieldRow, Flex, Select } from '@rocket.chat/fuselage';
import type { PathPattern } from '@rocket.chat/rest-typings';
import type { ReactElement } from 'react';
import React from 'react';
@@ -45,13 +45,13 @@ function LookupSettingInput({
<>
-
+
{label}
-
+
{hasResetButton && }
-
+
+
>
);
}
diff --git a/apps/meteor/client/views/admin/settings/inputs/MultiSelectSettingInput.tsx b/apps/meteor/client/views/admin/settings/inputs/MultiSelectSettingInput.tsx
index 114503c959ed..bc8d8062d8a2 100644
--- a/apps/meteor/client/views/admin/settings/inputs/MultiSelectSettingInput.tsx
+++ b/apps/meteor/client/views/admin/settings/inputs/MultiSelectSettingInput.tsx
@@ -1,4 +1,4 @@
-import { Field, Flex, Box, MultiSelectFiltered, MultiSelect } from '@rocket.chat/fuselage';
+import { FieldLabel, Flex, Box, MultiSelectFiltered, MultiSelect } from '@rocket.chat/fuselage';
import type { TranslationKey } from '@rocket.chat/ui-contexts';
import { useTranslation } from '@rocket.chat/ui-contexts';
import type { ReactElement } from 'react';
@@ -45,9 +45,9 @@ function MultiSelectSettingInput({
<>
-
+
{label}
-
+
{hasResetButton && }
diff --git a/apps/meteor/client/views/admin/settings/inputs/PasswordSettingInput.tsx b/apps/meteor/client/views/admin/settings/inputs/PasswordSettingInput.tsx
index 087d83b98a0d..b7d2c1d48d47 100644
--- a/apps/meteor/client/views/admin/settings/inputs/PasswordSettingInput.tsx
+++ b/apps/meteor/client/views/admin/settings/inputs/PasswordSettingInput.tsx
@@ -1,4 +1,4 @@
-import { Box, Field, Flex, PasswordInput } from '@rocket.chat/fuselage';
+import { Box, FieldLabel, FieldRow, Flex, PasswordInput } from '@rocket.chat/fuselage';
import type { EventHandler, ReactElement, SyntheticEvent } from 'react';
import React from 'react';
@@ -37,13 +37,13 @@ function PasswordSettingInput({
<>
-
+
{label}
-
+
{hasResetButton && }
-
+
-
+
>
);
}
diff --git a/apps/meteor/client/views/admin/settings/inputs/RelativeUrlSettingInput.tsx b/apps/meteor/client/views/admin/settings/inputs/RelativeUrlSettingInput.tsx
index 0541ea81eb36..b94581706757 100644
--- a/apps/meteor/client/views/admin/settings/inputs/RelativeUrlSettingInput.tsx
+++ b/apps/meteor/client/views/admin/settings/inputs/RelativeUrlSettingInput.tsx
@@ -1,4 +1,4 @@
-import { Box, Field, Flex, UrlInput } from '@rocket.chat/fuselage';
+import { Box, FieldLabel, Flex, UrlInput } from '@rocket.chat/fuselage';
import { useAbsoluteUrl } from '@rocket.chat/ui-contexts';
import type { EventHandler, ReactElement, SyntheticEvent } from 'react';
import React from 'react';
@@ -40,9 +40,9 @@ function RelativeUrlSettingInput({
<>
-
+
{label}
-
+
{hasResetButton && }
diff --git a/apps/meteor/client/views/admin/settings/inputs/RoomPickSettingInput.tsx b/apps/meteor/client/views/admin/settings/inputs/RoomPickSettingInput.tsx
index d44235afbde9..15423742ff91 100644
--- a/apps/meteor/client/views/admin/settings/inputs/RoomPickSettingInput.tsx
+++ b/apps/meteor/client/views/admin/settings/inputs/RoomPickSettingInput.tsx
@@ -1,5 +1,5 @@
import type { SettingValueRoomPick } from '@rocket.chat/core-typings';
-import { Box, Field, Flex } from '@rocket.chat/fuselage';
+import { Box, FieldLabel, FieldRow, Flex } from '@rocket.chat/fuselage';
import type { ReactElement } from 'react';
import React from 'react';
@@ -42,13 +42,13 @@ function RoomPickSettingInput({
<>
-
+
{label}
-
+
{hasResetButton && }
-
+
-
+
>
);
}
diff --git a/apps/meteor/client/views/admin/settings/inputs/SelectSettingInput.tsx b/apps/meteor/client/views/admin/settings/inputs/SelectSettingInput.tsx
index 28014d65d375..a6fa88f7ffe7 100644
--- a/apps/meteor/client/views/admin/settings/inputs/SelectSettingInput.tsx
+++ b/apps/meteor/client/views/admin/settings/inputs/SelectSettingInput.tsx
@@ -1,4 +1,4 @@
-import { Box, Field, Flex, Select } from '@rocket.chat/fuselage';
+import { Box, FieldLabel, FieldRow, Flex, Select } from '@rocket.chat/fuselage';
import type { TranslationKey } from '@rocket.chat/ui-contexts';
import { useTranslation } from '@rocket.chat/ui-contexts';
import type { ReactElement } from 'react';
@@ -43,13 +43,13 @@ function SelectSettingInput({
<>
-
+
{label}
-
+
{hasResetButton && }
-
+
+
>
);
}
diff --git a/apps/meteor/client/views/admin/settings/inputs/SelectTimezoneSettingInput.tsx b/apps/meteor/client/views/admin/settings/inputs/SelectTimezoneSettingInput.tsx
index 1478b8746583..12c5da28365c 100644
--- a/apps/meteor/client/views/admin/settings/inputs/SelectTimezoneSettingInput.tsx
+++ b/apps/meteor/client/views/admin/settings/inputs/SelectTimezoneSettingInput.tsx
@@ -1,4 +1,4 @@
-import { Box, Field, Flex, Select } from '@rocket.chat/fuselage';
+import { Box, FieldLabel, FieldRow, Flex, Select } from '@rocket.chat/fuselage';
import moment from 'moment-timezone';
import type { ReactElement } from 'react';
import React from 'react';
@@ -38,13 +38,13 @@ function SelectTimezoneSettingInput({
<>
-
+
{label}
-
+
{hasResetButton && }
-
+
+
>
);
}
diff --git a/apps/meteor/client/views/admin/settings/inputs/StringSettingInput.tsx b/apps/meteor/client/views/admin/settings/inputs/StringSettingInput.tsx
index 30b79e01683f..3d0ba78a127a 100644
--- a/apps/meteor/client/views/admin/settings/inputs/StringSettingInput.tsx
+++ b/apps/meteor/client/views/admin/settings/inputs/StringSettingInput.tsx
@@ -1,4 +1,4 @@
-import { Box, Field, Flex, TextAreaInput, TextInput } from '@rocket.chat/fuselage';
+import { Box, FieldLabel, FieldRow, Flex, TextAreaInput, TextInput } from '@rocket.chat/fuselage';
import type { EventHandler, ReactElement, SyntheticEvent } from 'react';
import React from 'react';
@@ -43,13 +43,13 @@ function StringSettingInput({
<>
-
+
{label}
-
+
{hasResetButton && }
-
+
{multiline ? (
)}
-
+
>
);
}
diff --git a/apps/meteor/client/views/admin/users/AdminUserForm.tsx b/apps/meteor/client/views/admin/users/AdminUserForm.tsx
index 334aca68b8f8..1912150b4a48 100644
--- a/apps/meteor/client/views/admin/users/AdminUserForm.tsx
+++ b/apps/meteor/client/views/admin/users/AdminUserForm.tsx
@@ -1,6 +1,10 @@
import type { AvatarObject, IUser, Serialized } from '@rocket.chat/core-typings';
import {
Field,
+ FieldLabel,
+ FieldRow,
+ FieldError,
+ FieldHint,
TextInput,
TextAreaInput,
PasswordInput,
@@ -179,8 +183,8 @@ const UserForm = ({ userData, onReload, ...props }: AdminUserFormProps) => {
)}
- {t('Name')}
-
+ {t('Name')}
+
{
/>
)}
/>
-
+
{errors?.name && (
-
+
{errors.name.message}
-
+
)}
- {t('Username')}
-
+ {t('Username')}
+
{
/>
)}
/>
-
+
{errors?.username && (
-
+
{errors.username.message}
-
+
)}
- {t('Email')}
-
+ {t('Email')}
+
{
/>
)}
/>
-
+
{errors?.email && (
-
+
{errors.email.message}
-
+
)}
- {t('Verified')}
-
+ {t('Verified')}
+
}
/>
-
+
- {t('StatusMessage')}
-
+ {t('StatusMessage')}
+
{
/>
)}
/>
-
+
{errors?.statusText && (
-
+
{errors.statusText.message}
-
+
)}
- {t('Bio')}
-
+ {t('Bio')}
+
{
/>
)}
/>
-
+
{errors?.bio && (
-
+
{errors.bio.message}
-
+
)}
- {t('Nickname')}
-
+ {t('Nickname')}
+
{
} />
)}
/>
-
+
{!setRandomPassword && (
- {t('Password')}
-
+ {t('Password')}
+
{
/>
)}
/>
-
+
{errors?.password && (
-
+
{errors.password.message}
-
+
)}
)}
- {t('Require_password_change')}
-
+ {t('Require_password_change')}
+
{
/>
)}
/>
-
+
- {t('Set_random_password_and_send_by_email')}
-
+ {t('Set_random_password_and_send_by_email')}
+
{
/>
)}
/>
-
+
{!isSmtpEnabled && (
-
)}
- {t('Roles')}
-
+ {t('Roles')}
+
{roleError && {roleError}}
{!roleError && (
{
)}
/>
)}
-
- {errors?.roles && {errors.roles.message}}
+
+ {errors?.roles && {errors.roles.message}}
- {t('Join_default_channels')}
-
+ {t('Join_default_channels')}
+
{
)}
/>
-
+
- {t('Send_welcome_email')}
-
+ {t('Send_welcome_email')}
+
{
/>
)}
/>
-
+
{!isSmtpEnabled && (
-
diff --git a/apps/meteor/client/views/e2e/EnterE2EPasswordModal.tsx b/apps/meteor/client/views/e2e/EnterE2EPasswordModal.tsx
index 76d5f3b61e28..249ae6df5efa 100644
--- a/apps/meteor/client/views/e2e/EnterE2EPasswordModal.tsx
+++ b/apps/meteor/client/views/e2e/EnterE2EPasswordModal.tsx
@@ -1,4 +1,4 @@
-import { Box, PasswordInput, Field, FieldGroup } from '@rocket.chat/fuselage';
+import { Box, PasswordInput, Field, FieldGroup, FieldRow, FieldError } from '@rocket.chat/fuselage';
import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
import { useTranslation } from '@rocket.chat/ui-contexts';
import type { ReactElement } from 'react';
@@ -50,7 +50,7 @@ const EnterE2EPasswordModal = ({
-
+
-
- {passwordError}
+
+ {passwordError}
diff --git a/apps/meteor/client/views/omnichannel/agents/AgentEdit.tsx b/apps/meteor/client/views/omnichannel/agents/AgentEdit.tsx
index b6b536925ba1..aa5a917405b4 100644
--- a/apps/meteor/client/views/omnichannel/agents/AgentEdit.tsx
+++ b/apps/meteor/client/views/omnichannel/agents/AgentEdit.tsx
@@ -1,5 +1,17 @@
import type { ILivechatAgent, ILivechatDepartment, ILivechatDepartmentAgents } from '@rocket.chat/core-typings';
-import { Field, TextInput, Button, Box, MultiSelect, Icon, Select, ContextualbarFooter, ButtonGroup } from '@rocket.chat/fuselage';
+import {
+ Field,
+ FieldLabel,
+ FieldRow,
+ TextInput,
+ Button,
+ Box,
+ MultiSelect,
+ Icon,
+ Select,
+ ContextualbarFooter,
+ ButtonGroup,
+} from '@rocket.chat/fuselage';
import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
import { useToastMessageDispatch, useRoute, useSetting, useMethod, useTranslation, useEndpoint } from '@rocket.chat/ui-contexts';
import type { FC, ReactElement } from 'react';
@@ -121,26 +133,26 @@ const AgentEdit: FC = ({ data, userDepartments, availableDepartm
)}
- {t('Name')}
-
+ {t('Name')}
+
-
+
- {t('Username')}
-
+ {t('Username')}
+
} />
-
+
- {t('Email')}
-
+ {t('Email')}
+
} />
-
+
- {t('Departments')}
-
+ {t('Departments')}
+
= ({ data, userDepartments, availableDepartm
placeholder={t('Select_an_option')}
onChange={handleDepartments}
/>
-
+
- {t('Status')}
-
+ {t('Status')}
+
+
{MaxChats && }
{voipEnabled && (
- {t('VoIP_Extension')}
-
+ {t('VoIP_Extension')}
+
-
+
)}
diff --git a/apps/meteor/client/views/omnichannel/agents/AgentsTable/AddAgent.tsx b/apps/meteor/client/views/omnichannel/agents/AgentsTable/AddAgent.tsx
index e030fe3d6305..47d60b3d9958 100644
--- a/apps/meteor/client/views/omnichannel/agents/AgentsTable/AddAgent.tsx
+++ b/apps/meteor/client/views/omnichannel/agents/AgentsTable/AddAgent.tsx
@@ -1,4 +1,4 @@
-import { Button, Box, Field } from '@rocket.chat/fuselage';
+import { Button, Box, Field, FieldLabel, FieldRow } from '@rocket.chat/fuselage';
import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
import { useToastMessageDispatch, useTranslation } from '@rocket.chat/ui-contexts';
import type { ReactElement } from 'react';
@@ -38,13 +38,13 @@ const AddAgent = ({ reload }: AddAgentProps): ReactElement => {
return (
- {t('Username')}
-
+ {t('Username')}
+
-
+
);
diff --git a/apps/meteor/client/views/omnichannel/analytics/AnalyticsPage.tsx b/apps/meteor/client/views/omnichannel/analytics/AnalyticsPage.tsx
index 333d2e772c4c..4a7405b7b8cc 100644
--- a/apps/meteor/client/views/omnichannel/analytics/AnalyticsPage.tsx
+++ b/apps/meteor/client/views/omnichannel/analytics/AnalyticsPage.tsx
@@ -1,5 +1,5 @@
import type { SelectOption } from '@rocket.chat/fuselage';
-import { Box, Select, Margins, Field, Label } from '@rocket.chat/fuselage';
+import { Box, Select, Margins, Field, FieldLabel, FieldRow, Label } from '@rocket.chat/fuselage';
import { useTranslation } from '@rocket.chat/ui-contexts';
import React, { useMemo, useState, useEffect } from 'react';
@@ -74,10 +74,10 @@ const AnalyticsPage = () => {
- {t('Chart')}
-
+ {t('Chart')}
+
+
diff --git a/apps/meteor/client/views/omnichannel/analytics/DateRangePicker.tsx b/apps/meteor/client/views/omnichannel/analytics/DateRangePicker.tsx
index b84996f168d4..40644b1f1b04 100644
--- a/apps/meteor/client/views/omnichannel/analytics/DateRangePicker.tsx
+++ b/apps/meteor/client/views/omnichannel/analytics/DateRangePicker.tsx
@@ -1,4 +1,4 @@
-import { Box, InputBox, Menu, Field } from '@rocket.chat/fuselage';
+import { Box, InputBox, Menu, Field, FieldLabel, FieldRow } from '@rocket.chat/fuselage';
import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
import { useTranslation } from '@rocket.chat/ui-contexts';
import type { Moment } from 'moment';
@@ -112,21 +112,21 @@ const DateRangePicker = ({ onChange = () => undefined, ...props }: DateRangePick
- {t('Start')}
-
+ {t('Start')}
+
-
+
- {t('End')}
-
+ {t('End')}
+
-
+
diff --git a/apps/meteor/client/views/omnichannel/appearance/AppearanceForm.tsx b/apps/meteor/client/views/omnichannel/appearance/AppearanceForm.tsx
index 9d5e176301a8..4983c5ca8837 100644
--- a/apps/meteor/client/views/omnichannel/appearance/AppearanceForm.tsx
+++ b/apps/meteor/client/views/omnichannel/appearance/AppearanceForm.tsx
@@ -1,4 +1,16 @@
-import { Box, Field, TextInput, ToggleSwitch, Accordion, FieldGroup, InputBox, TextAreaInput, NumberInput } from '@rocket.chat/fuselage';
+import {
+ Box,
+ Field,
+ FieldLabel,
+ FieldRow,
+ TextInput,
+ ToggleSwitch,
+ Accordion,
+ FieldGroup,
+ InputBox,
+ TextAreaInput,
+ NumberInput,
+} from '@rocket.chat/fuselage';
import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
import { useTranslation } from '@rocket.chat/ui-contexts';
import type { FC, FormEvent } from 'react';
@@ -105,46 +117,46 @@ const AppearanceForm: FC = ({ values = {}, handlers = {} })
- {t('Title')}
-
+ {t('Title')}
+
-
+
- {t('Title_bar_color')}
-
+ {t('Title_bar_color')}
+
-
+
- {t('Message_Characther_Limit')}
-
+ {t('Message_Characther_Limit')}
+
-
+
-
+
-
+
- {t('Show_agent_info')}
-
+ {t('Show_agent_info')}
+
-
+
- {t('Show_agent_email')}
-
+ {t('Show_agent_email')}
+
-
+
@@ -154,66 +166,66 @@ const AppearanceForm: FC = ({ values = {}, handlers = {} })
- {t('Display_offline_form')}
-
+ {t('Display_offline_form')}
+
-
+
- {t('Offline_form_unavailable_message')}
-
+ {t('Offline_form_unavailable_message')}
+
-
+
- {t('Offline_message')}
-
+ {t('Offline_message')}
+
-
+
- {t('Title_offline')}
-
+ {t('Title_offline')}
+
-
+
- {t('Title_bar_color_offline')}
-
+ {t('Title_bar_color_offline')}
+
-
+
- {t('Email_address_to_send_offline_messages')}
-
+ {t('Email_address_to_send_offline_messages')}
+
-
+
- {t('Offline_success_message')}
-
+ {t('Offline_success_message')}
+
-
+
@@ -222,64 +234,64 @@ const AppearanceForm: FC = ({ values = {}, handlers = {} })
- {t('Enabled')}
-
+ {t('Enabled')}
+
-
+
- {t('Show_name_field')}
-
+ {t('Show_name_field')}
+
-
+
- {t('Show_email_field')}
-
+ {t('Show_email_field')}
+
-
+
- {t('Livechat_registration_form_message')}
-
+ {t('Livechat_registration_form_message')}
+
-
+
- {t('Conversation_finished_message')}
-
+ {t('Conversation_finished_message')}
+
-
+
- {t('Conversation_finished_text')}
-
+ {t('Conversation_finished_text')}
+
-
+
diff --git a/apps/meteor/client/views/omnichannel/currentChats/CustomFieldsList.tsx b/apps/meteor/client/views/omnichannel/currentChats/CustomFieldsList.tsx
index e0b8a77381b4..803b74b9522d 100644
--- a/apps/meteor/client/views/omnichannel/currentChats/CustomFieldsList.tsx
+++ b/apps/meteor/client/views/omnichannel/currentChats/CustomFieldsList.tsx
@@ -1,5 +1,5 @@
import type { ILivechatCustomField } from '@rocket.chat/core-typings';
-import { Field, TextInput, Select } from '@rocket.chat/fuselage';
+import { Field, FieldLabel, FieldRow, TextInput, Select } from '@rocket.chat/fuselage';
import { useTranslation, useRoute } from '@rocket.chat/ui-contexts';
import type { ReactElement, Dispatch, SetStateAction } from 'react';
import React, { useEffect } from 'react';
@@ -39,8 +39,8 @@ const CustomFieldsList = ({ setCustomFields, allCustomFields }: CustomFieldsList
if (customField.type === 'select') {
return (
- {customField.label}
-
+ {customField.label}
+
[item, item])} />
)}
/>
-
+
);
}
return (
- {customField.label}
-
+ {customField.label}
+
-
+
);
})}
diff --git a/apps/meteor/client/views/omnichannel/departments/DepartmentTags/index.tsx b/apps/meteor/client/views/omnichannel/departments/DepartmentTags/index.tsx
index b1542f857316..cead6a0fb15f 100644
--- a/apps/meteor/client/views/omnichannel/departments/DepartmentTags/index.tsx
+++ b/apps/meteor/client/views/omnichannel/departments/DepartmentTags/index.tsx
@@ -1,4 +1,4 @@
-import { Button, Chip, Field, TextInput } from '@rocket.chat/fuselage';
+import { Button, Chip, FieldRow, FieldHint, TextInput } from '@rocket.chat/fuselage';
import { useTranslation } from '@rocket.chat/ui-contexts';
import type { FormEvent } from 'react';
import React, { useCallback, useState } from 'react';
@@ -28,7 +28,7 @@ export const DepartmentTags = ({ error, value: tags, onChange }: DepartmentTagsP
return (
<>
-
+
{t('Add')}
-
+
- {t('Conversation_closing_tags_description')}
+ {t('Conversation_closing_tags_description')}
{tags?.length > 0 && (
-
+
{tags.map((tag, i) => (
{tag}
))}
-
+
)}
>
);
diff --git a/apps/meteor/client/views/omnichannel/departments/EditDepartment.tsx b/apps/meteor/client/views/omnichannel/departments/EditDepartment.tsx
index 3a408bfa7507..46919307b052 100644
--- a/apps/meteor/client/views/omnichannel/departments/EditDepartment.tsx
+++ b/apps/meteor/client/views/omnichannel/departments/EditDepartment.tsx
@@ -2,6 +2,9 @@ import type { ILivechatDepartment, ILivechatDepartmentAgents, Serialized } from
import {
FieldGroup,
Field,
+ FieldLabel,
+ FieldRow,
+ FieldError,
TextInput,
Box,
Icon,
@@ -240,16 +243,16 @@ function EditDepartment({ data, id, title, allowedToForwardData }: EditDepartmen
>
- {t('Enabled')}
-
+ {t('Enabled')}
+
-
+
- {t('Name')}*
-
+ {t('Name')}*
+
-
- {errors.name && {errors.name?.message}}
+
+ {errors.name && {errors.name?.message}}
- {t('Description')}
-
+ {t('Description')}
+
-
+
- {t('Show_on_registration_page')}
-
+ {t('Show_on_registration_page')}
+
-
+
- {t('Email')}*
-
+ {t('Email')}*
+
validateEmail(email) || t('error-invalid-email-address'),
})}
/>
-
- {errors.email && {errors.email?.message}}
+
+ {errors.email && {errors.email?.message}}
- {t('Show_on_offline_page')}
-
+ {t('Show_on_offline_page')}
+
-
+
- {t('Livechat_DepartmentOfflineMessageToChannel')}
-
+ {t('Livechat_DepartmentOfflineMessageToChannel')}
+
)}
/>
-
+
{MaxChats && (
@@ -421,7 +424,7 @@ function EditDepartment({ data, id, title, allowedToForwardData }: EditDepartmen
{AutoCompleteDepartment && (
- {t('Fallback_forward_department')}
+ {t('Fallback_forward_department')}
- {t('Request_tag_before_closing_chat')}
-
+ {t('Request_tag_before_closing_chat')}
+
-
+
{requestTagBeforeClosingChat && (
- {t('Conversation_closing_tags')}*
+ {t('Conversation_closing_tags')}*
)}
/>
- {errors.chatClosingTags && {errors.chatClosingTags?.message}}
+ {errors.chatClosingTags && {errors.chatClosingTags?.message}}
)}
@@ -475,7 +478,7 @@ function EditDepartment({ data, id, title, allowedToForwardData }: EditDepartmen
- {t('Agents')}:
+ {t('Agents')}:
diff --git a/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/RoomEdit/RoomEdit.tsx b/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/RoomEdit/RoomEdit.tsx
index 433af2135068..89b7b4582fa5 100644
--- a/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/RoomEdit/RoomEdit.tsx
+++ b/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/RoomEdit/RoomEdit.tsx
@@ -1,5 +1,5 @@
import type { ILivechatVisitor, IOmnichannelRoom, Serialized } from '@rocket.chat/core-typings';
-import { Field, TextInput, ButtonGroup, Button } from '@rocket.chat/fuselage';
+import { Field, FieldLabel, FieldRow, TextInput, ButtonGroup, Button } from '@rocket.chat/fuselage';
import { CustomFieldsForm } from '@rocket.chat/ui-client';
import { useToastMessageDispatch, useTranslation, useEndpoint } from '@rocket.chat/ui-contexts';
import { useQueryClient } from '@tanstack/react-query';
@@ -127,10 +127,10 @@ function RoomEdit({ room, visitor, reload, reloadInfo, onClose }: RoomEditProps)
)}
- {t('Topic')}
-
+ {t('Topic')}
+
-
+
diff --git a/apps/meteor/client/views/omnichannel/directory/contacts/contextualBar/ContactNewEdit.tsx b/apps/meteor/client/views/omnichannel/directory/contacts/contextualBar/ContactNewEdit.tsx
index afb609e5f801..a41c155c4f9d 100644
--- a/apps/meteor/client/views/omnichannel/directory/contacts/contextualBar/ContactNewEdit.tsx
+++ b/apps/meteor/client/views/omnichannel/directory/contacts/contextualBar/ContactNewEdit.tsx
@@ -1,5 +1,5 @@
import type { ILivechatVisitor, Serialized } from '@rocket.chat/core-typings';
-import { Field, TextInput, ButtonGroup, Button, ContextualbarContent } from '@rocket.chat/fuselage';
+import { Field, FieldLabel, FieldRow, FieldError, TextInput, ButtonGroup, Button, ContextualbarContent } from '@rocket.chat/fuselage';
import { CustomFieldsForm } from '@rocket.chat/ui-client';
import { useToastMessageDispatch, useEndpoint, useTranslation } from '@rocket.chat/ui-contexts';
import { useQueryClient } from '@tanstack/react-query';
@@ -189,25 +189,25 @@ const ContactNewEdit = ({ id, data, close }: ContactNewEditProps): ReactElement
<>
- {t('Name')}*
-
+ {t('Name')}*
+
-
- {errors.name?.message}
+
+ {errors.name?.message}
- {t('Email')}
-
+ {t('Email')}
+
-
- {errors.email?.message}
+
+ {errors.email?.message}
- {t('Phone')}
-
+ {t('Phone')}
+
-
- {errors.phone?.message}
+
+ {errors.phone?.message}
{canViewCustomFields() && }
{ContactManager && }
diff --git a/apps/meteor/client/views/omnichannel/managers/AddManager.tsx b/apps/meteor/client/views/omnichannel/managers/AddManager.tsx
index d6668d7f35d7..b4f56f78b62b 100644
--- a/apps/meteor/client/views/omnichannel/managers/AddManager.tsx
+++ b/apps/meteor/client/views/omnichannel/managers/AddManager.tsx
@@ -1,4 +1,4 @@
-import { Button, Box, Field } from '@rocket.chat/fuselage';
+import { Button, Box, Field, FieldLabel, FieldRow } from '@rocket.chat/fuselage';
import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
import { useToastMessageDispatch, useTranslation } from '@rocket.chat/ui-contexts';
import type { ReactElement } from 'react';
@@ -34,13 +34,13 @@ const AddManager = ({ reload }: { reload: () => void }): ReactElement => {
return (
- {t('Username')}
-
+ {t('Username')}
+
-
+
);
diff --git a/apps/meteor/client/views/omnichannel/triggers/TriggersForm.tsx b/apps/meteor/client/views/omnichannel/triggers/TriggersForm.tsx
index 72c8d30d973e..7c9476059411 100644
--- a/apps/meteor/client/views/omnichannel/triggers/TriggersForm.tsx
+++ b/apps/meteor/client/views/omnichannel/triggers/TriggersForm.tsx
@@ -1,5 +1,5 @@
import type { SelectOption } from '@rocket.chat/fuselage';
-import { Box, Field, TextInput, ToggleSwitch, Select, TextAreaInput } from '@rocket.chat/fuselage';
+import { Box, Field, FieldLabel, FieldRow, FieldError, TextInput, ToggleSwitch, Select, TextAreaInput } from '@rocket.chat/fuselage';
import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
import { useTranslation } from '@rocket.chat/ui-contexts';
import type { ComponentProps, FC, FormEvent } from 'react';
@@ -138,55 +138,55 @@ const TriggersForm: FC = ({ values, handlers, className }) =>
<>
- {t('Enabled')}
-
+ {t('Enabled')}
+
-
+
- {t('Run_only_once_for_each_visitor')}
-
+ {t('Run_only_once_for_each_visitor')}
+
-
+
- {t('Name')}*
-
+ {t('Name')}*
+
-
- {nameError}
+
+ {nameError}
- {t('Description')}
-
+ {t('Description')}
+
-
+
- {t('Condition')}
-
+ {t('Condition')}
+
-
+
{conditionValuePlaceholder && (
-
+
-
+
)}
- {t('Action')}
-
+ {t('Action')}
+
-
-
+
+
+
{actionSender === 'custom' && (
-
+
-
+
)}
-
+
-
- {msgError}
+
+ {msgError}
>
);
diff --git a/apps/meteor/client/views/room/contextualBar/AutoTranslate/AutoTranslate.tsx b/apps/meteor/client/views/room/contextualBar/AutoTranslate/AutoTranslate.tsx
index a15edebf8c16..6952b5b1dafe 100644
--- a/apps/meteor/client/views/room/contextualBar/AutoTranslate/AutoTranslate.tsx
+++ b/apps/meteor/client/views/room/contextualBar/AutoTranslate/AutoTranslate.tsx
@@ -1,4 +1,4 @@
-import { FieldGroup, Field, ToggleSwitch, Select } from '@rocket.chat/fuselage';
+import { FieldGroup, Field, FieldLabel, FieldRow, ToggleSwitch, Select } from '@rocket.chat/fuselage';
import type { SelectOption } from '@rocket.chat/fuselage';
import { useTranslation } from '@rocket.chat/ui-contexts';
import type { ReactElement, ChangeEvent } from 'react';
@@ -41,14 +41,14 @@ const AutoTranslate = ({
-
+
- {t('Automatic_Translation')}
-
+ {t('Automatic_Translation')}
+
- {t('Language')}
-
+ {t('Language')}
+
+
diff --git a/apps/meteor/client/views/room/contextualBar/ExportMessages/ExportMessages.tsx b/apps/meteor/client/views/room/contextualBar/ExportMessages/ExportMessages.tsx
index 1bf59d4e8de7..28b8b56a1df2 100644
--- a/apps/meteor/client/views/room/contextualBar/ExportMessages/ExportMessages.tsx
+++ b/apps/meteor/client/views/room/contextualBar/ExportMessages/ExportMessages.tsx
@@ -1,5 +1,5 @@
import type { SelectOption } from '@rocket.chat/fuselage';
-import { Field, Select, FieldGroup } from '@rocket.chat/fuselage';
+import { Field, Select, FieldGroup, FieldLabel, FieldRow } from '@rocket.chat/fuselage';
import { useTranslation } from '@rocket.chat/ui-contexts';
import React, { useState, useMemo } from 'react';
@@ -40,10 +40,10 @@ const ExportMessages = () => {
- {t('Method')}
-
+ {t('Method')}
+
+
{type && type === 'file' && }
diff --git a/apps/meteor/client/views/room/contextualBar/ExportMessages/FileExport.tsx b/apps/meteor/client/views/room/contextualBar/ExportMessages/FileExport.tsx
index efbf60b69606..2085e11ea11d 100644
--- a/apps/meteor/client/views/room/contextualBar/ExportMessages/FileExport.tsx
+++ b/apps/meteor/client/views/room/contextualBar/ExportMessages/FileExport.tsx
@@ -1,6 +1,6 @@
import type { IRoom } from '@rocket.chat/core-typings';
import type { SelectOption } from '@rocket.chat/fuselage';
-import { Field, Select, ButtonGroup, Button, FieldGroup, InputBox } from '@rocket.chat/fuselage';
+import { Field, FieldLabel, FieldRow, Select, ButtonGroup, Button, FieldGroup, InputBox } from '@rocket.chat/fuselage';
import { useToastMessageDispatch, useEndpoint, useTranslation } from '@rocket.chat/ui-contexts';
import type { FC, MouseEventHandler } from 'react';
import React, { useMemo } from 'react';
@@ -65,22 +65,22 @@ const FileExport: FC = ({ onCancel, rid }) => {
return (
- {t('Date_From')}
-
+ {t('Date_From')}
+
-
+
- {t('Date_to')}
-
+ {t('Date_to')}
+
-
+
- {t('Output_format')}
-
+ {t('Output_format')}
+
-
+
diff --git a/apps/meteor/client/views/room/contextualBar/ExportMessages/MailExportForm.tsx b/apps/meteor/client/views/room/contextualBar/ExportMessages/MailExportForm.tsx
index f44e94ed69cc..c8ae5a96300d 100644
--- a/apps/meteor/client/views/room/contextualBar/ExportMessages/MailExportForm.tsx
+++ b/apps/meteor/client/views/room/contextualBar/ExportMessages/MailExportForm.tsx
@@ -1,6 +1,6 @@
import type { IRoom } from '@rocket.chat/core-typings';
import { css } from '@rocket.chat/css-in-js';
-import { Field, TextInput, ButtonGroup, Button, Box, Icon, Callout, FieldGroup } from '@rocket.chat/fuselage';
+import { Field, FieldLabel, FieldRow, TextInput, ButtonGroup, Button, Box, Icon, Callout, FieldGroup } from '@rocket.chat/fuselage';
import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
import { useToastMessageDispatch, useUserRoom, useEndpoint, useTranslation } from '@rocket.chat/ui-contexts';
import type { FC, MouseEventHandler } from 'react';
@@ -116,27 +116,27 @@ const MailExportForm: FC = ({ onCancel, rid }) => {
- {t('To_users')}
-
+ {t('To_users')}
+
-
+
- {t('To_additional_emails')}
-
+ {t('To_additional_emails')}
+
}
/>
-
+
- {t('Subject')}
-
+ {t('Subject')}
+
} />
-
+
{errorMessage && {errorMessage}}
diff --git a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchForm.tsx b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchForm.tsx
index bc25f538643d..f1f69f9299f3 100644
--- a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchForm.tsx
+++ b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchForm.tsx
@@ -1,5 +1,5 @@
import type { IMessageSearchProvider } from '@rocket.chat/core-typings';
-import { Box, Field, Icon, TextInput, ToggleSwitch } from '@rocket.chat/fuselage';
+import { Box, Field, FieldLabel, FieldRow, FieldHint, Icon, TextInput, ToggleSwitch } from '@rocket.chat/fuselage';
import { useDebouncedCallback, useMutableCallback, useUniqueId } from '@rocket.chat/fuselage-hooks';
import type { TranslationKey } from '@rocket.chat/ui-contexts';
import { useTranslation } from '@rocket.chat/ui-contexts';
@@ -55,7 +55,7 @@ const MessageSearchForm = ({ provider, onSearch }: MessageSearchFormProps) => {
>
-
+
}
placeholder={t('Search_Messages')}
@@ -63,15 +63,15 @@ const MessageSearchForm = ({ provider, onSearch }: MessageSearchFormProps) => {
autoComplete='off'
{...register('searchText')}
/>
-
- {provider.description && }
+
+ {provider.description && }
{globalSearchEnabled && (
-
+
- {t('Global_Search')}
-
+ {t('Global_Search')}
+
)}
diff --git a/apps/meteor/client/views/room/contextualBar/NotificationPreferences/components/NotificationPreference.tsx b/apps/meteor/client/views/room/contextualBar/NotificationPreferences/components/NotificationPreference.tsx
index f187312e12ea..c89584bd1eef 100644
--- a/apps/meteor/client/views/room/contextualBar/NotificationPreferences/components/NotificationPreference.tsx
+++ b/apps/meteor/client/views/room/contextualBar/NotificationPreferences/components/NotificationPreference.tsx
@@ -1,5 +1,5 @@
import type { SelectOption } from '@rocket.chat/fuselage';
-import { Field, Select } from '@rocket.chat/fuselage';
+import { Field, FieldLabel, FieldRow, Select } from '@rocket.chat/fuselage';
import type { ReactElement } from 'react';
import React from 'react';
@@ -21,11 +21,11 @@ const NotificationPreference = ({
...props
}: NotificationPreferenceProps): ReactElement => (
- {name}
-
+ {name}
+
{children}
-
+
);
diff --git a/apps/meteor/client/views/room/contextualBar/PruneMessages/PruneMessages.tsx b/apps/meteor/client/views/room/contextualBar/PruneMessages/PruneMessages.tsx
index 9f64bbc6504b..709699ebd697 100644
--- a/apps/meteor/client/views/room/contextualBar/PruneMessages/PruneMessages.tsx
+++ b/apps/meteor/client/views/room/contextualBar/PruneMessages/PruneMessages.tsx
@@ -1,4 +1,4 @@
-import { Field, ButtonGroup, Button, CheckBox, Callout } from '@rocket.chat/fuselage';
+import { Field, FieldLabel, FieldRow, ButtonGroup, Button, CheckBox, Callout } from '@rocket.chat/fuselage';
import { useUniqueId } from '@rocket.chat/fuselage-hooks';
import { useTranslation } from '@rocket.chat/ui-contexts';
import type { ReactElement } from 'react';
@@ -45,7 +45,7 @@ const PruneMessages = ({ callOutText, validateText, onClickClose, onClickPrune }
- {t('Only_from_users')}
+ {t('Only_from_users')}
-
+
- {t('Inclusive')}
-
+ {t('Inclusive')}
+
-
+
- {t('RetentionPolicy_DoNotPrunePinned')}
-
+ {t('RetentionPolicy_DoNotPrunePinned')}
+
-
+
- {t('RetentionPolicy_DoNotPruneDiscussion')}
-
+ {t('RetentionPolicy_DoNotPruneDiscussion')}
+
-
+
- {t('RetentionPolicy_DoNotPruneThreads')}
-
+ {t('RetentionPolicy_DoNotPruneThreads')}
+
-
+
- {t('Files_only')}
-
+ {t('Files_only')}
+
{callOutText && !validateText && {callOutText}}
{validateText && {validateText}}
diff --git a/apps/meteor/client/views/room/contextualBar/PruneMessages/PruneMessagesDateTimeRow.tsx b/apps/meteor/client/views/room/contextualBar/PruneMessages/PruneMessagesDateTimeRow.tsx
index e774311e5564..38bf1c233f5a 100644
--- a/apps/meteor/client/views/room/contextualBar/PruneMessages/PruneMessagesDateTimeRow.tsx
+++ b/apps/meteor/client/views/room/contextualBar/PruneMessages/PruneMessagesDateTimeRow.tsx
@@ -1,4 +1,4 @@
-import { Field, InputBox, Box, Margins } from '@rocket.chat/fuselage';
+import { Field, FieldLabel, InputBox, Box, Margins } from '@rocket.chat/fuselage';
import type { ReactElement } from 'react';
import React from 'react';
import { useFormContext } from 'react-hook-form';
@@ -13,7 +13,7 @@ const PruneMessagesDateTimeRow = ({ label, field }: PruneMessagesDateTimeRowProp
return (
- {label}
+ {label}
diff --git a/apps/meteor/client/views/room/contextualBar/RoomMembers/AddUsers/AddUsers.tsx b/apps/meteor/client/views/room/contextualBar/RoomMembers/AddUsers/AddUsers.tsx
index 7a8f0d1e699a..09eaca08cbc9 100644
--- a/apps/meteor/client/views/room/contextualBar/RoomMembers/AddUsers/AddUsers.tsx
+++ b/apps/meteor/client/views/room/contextualBar/RoomMembers/AddUsers/AddUsers.tsx
@@ -1,6 +1,6 @@
import type { IRoom } from '@rocket.chat/core-typings';
import { isRoomFederated } from '@rocket.chat/core-typings';
-import { Field, Button, ButtonGroup, FieldGroup } from '@rocket.chat/fuselage';
+import { Field, FieldLabel, Button, ButtonGroup, FieldGroup } from '@rocket.chat/fuselage';
import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
import { useToastMessageDispatch, useMethod, useTranslation } from '@rocket.chat/ui-contexts';
import type { ReactElement } from 'react';
@@ -65,7 +65,7 @@ const AddUsers = ({ rid, onClickBack, reload }: AddUsersProps): ReactElement =>
- {t('Choose_users')}
+ {t('Choose_users')}
{isRoomFederated(room) ? (
- {t('Expiration_(Days)')}
-
+ {t('Expiration_(Days)')}
+
)}
/>
-
+
- {t('Max_number_of_uses')}
-
+ {t('Max_number_of_uses')}
+
)}
/>
-
+
-
+
-
- {errors.description && {t('You_need_to_write_something')}}
+
+ {errors.description && {t('You_need_to_write_something')}}
diff --git a/apps/meteor/client/views/room/webdav/AddWebdavAccountModal.tsx b/apps/meteor/client/views/room/webdav/AddWebdavAccountModal.tsx
index cff38579dfdb..4709e5296997 100644
--- a/apps/meteor/client/views/room/webdav/AddWebdavAccountModal.tsx
+++ b/apps/meteor/client/views/room/webdav/AddWebdavAccountModal.tsx
@@ -1,5 +1,5 @@
import type { IWebdavAccountPayload } from '@rocket.chat/core-typings';
-import { Modal, Field, FieldGroup, TextInput, PasswordInput, Button, Box } from '@rocket.chat/fuselage';
+import { Modal, Field, FieldGroup, FieldLabel, FieldRow, FieldError, TextInput, PasswordInput, Button, Box } from '@rocket.chat/fuselage';
import { useToastMessageDispatch, useMethod, useTranslation } from '@rocket.chat/ui-contexts';
import type { ReactElement } from 'react';
import React, { useState } from 'react';
@@ -47,31 +47,31 @@ const AddWebdavAccountModal = ({ onClose, onConfirm }: AddWebdavAccountModalProp
- {t('Name_optional')}
-
+ {t('Name_optional')}
+
-
+
- {t('Webdav_Server_URL')}
-
+ {t('Webdav_Server_URL')}
+
-
- {errors.serverURL && {t('error-the-field-is-required', { field: t('Webdav_Server_URL') })}}
+
+ {errors.serverURL && {t('error-the-field-is-required', { field: t('Webdav_Server_URL') })}}
- {t('Username')}
-
+ {t('Username')}
+
-
- {errors.username && {t('error-the-field-is-required', { field: t('Username') })}}
+
+ {errors.username && {t('error-the-field-is-required', { field: t('Username') })}}
- {t('Password')}
-
+ {t('Password')}
+
-
- {errors.password && {t('error-the-field-is-required', { field: t('Password') })}}
+
+ {errors.password && {t('error-the-field-is-required', { field: t('Password') })}}
diff --git a/apps/meteor/client/views/room/webdav/SaveToWebdavModal.tsx b/apps/meteor/client/views/room/webdav/SaveToWebdavModal.tsx
index d0de433be954..5cc2ccdd48b4 100644
--- a/apps/meteor/client/views/room/webdav/SaveToWebdavModal.tsx
+++ b/apps/meteor/client/views/room/webdav/SaveToWebdavModal.tsx
@@ -1,6 +1,6 @@
import type { MessageAttachment, IWebdavAccount } from '@rocket.chat/core-typings';
import type { SelectOption } from '@rocket.chat/fuselage';
-import { Modal, Box, Button, FieldGroup, Field, Select, Throbber } from '@rocket.chat/fuselage';
+import { Modal, Box, Button, FieldGroup, Field, FieldLabel, FieldRow, FieldError, Select, Throbber } from '@rocket.chat/fuselage';
import { useUniqueId } from '@rocket.chat/fuselage-hooks';
import { useMethod, useToastMessageDispatch, useTranslation } from '@rocket.chat/ui-contexts';
import type { ReactElement } from 'react';
@@ -95,8 +95,8 @@ const SaveToWebdavModal = ({ onClose, data }: SaveToWebdavModalProps): ReactElem
{!isLoading && (
- {t('Select_a_webdav_server')}
-
+ {t('Select_a_webdav_server')}
+
)}
/>
-
- {errors.accountId && {t('Field_required')}}
+
+ {errors.accountId && {t('Field_required')}}
)}
diff --git a/apps/meteor/client/views/root/MainLayout/RegisterUsername.tsx b/apps/meteor/client/views/root/MainLayout/RegisterUsername.tsx
index e7dae770c444..fec006cec966 100644
--- a/apps/meteor/client/views/root/MainLayout/RegisterUsername.tsx
+++ b/apps/meteor/client/views/root/MainLayout/RegisterUsername.tsx
@@ -1,5 +1,5 @@
import type { IUser } from '@rocket.chat/core-typings';
-import { TextInput, ButtonGroup, Button, FieldGroup, Field, Box } from '@rocket.chat/fuselage';
+import { TextInput, ButtonGroup, Button, FieldGroup, Field, FieldLabel, FieldRow, FieldError, Box } from '@rocket.chat/fuselage';
import { useUniqueId } from '@rocket.chat/fuselage-hooks';
import { VerticalWizardLayout, Form } from '@rocket.chat/layout';
import { CustomFieldsForm } from '@rocket.chat/ui-client';
@@ -102,11 +102,11 @@ const RegisterUsername = () => {
{!isLoading && (
- {t('Username')}
-
+ {t('Username')}
+
-
- {errors.username && {errors.username.message}}
+
+ {errors.username && {errors.username.message}}
)}
diff --git a/apps/meteor/client/views/teams/contextualBar/channels/AddExistingModal/AddExistingModal.tsx b/apps/meteor/client/views/teams/contextualBar/channels/AddExistingModal/AddExistingModal.tsx
index 3bc913338094..4fa5828d462f 100644
--- a/apps/meteor/client/views/teams/contextualBar/channels/AddExistingModal/AddExistingModal.tsx
+++ b/apps/meteor/client/views/teams/contextualBar/channels/AddExistingModal/AddExistingModal.tsx
@@ -1,4 +1,4 @@
-import { Box, Button, Field, Modal } from '@rocket.chat/fuselage';
+import { Box, Button, Field, FieldLabel, Modal } from '@rocket.chat/fuselage';
import { useToastMessageDispatch, useEndpoint, useTranslation } from '@rocket.chat/ui-contexts';
import React, { memo, useCallback } from 'react';
import { useForm, Controller } from 'react-hook-form';
@@ -48,7 +48,7 @@ const AddExistingModal = ({ onClose, teamId }: AddExistingModalProps) => {
- {t('Channels')}
+ {t('Channels')}
- {t('Business_Hour')}
-
+ {t('Business_Hour')}
+
-
+
);
};
diff --git a/apps/meteor/ee/client/omnichannel/additionalForms/DepartmentForwarding.tsx b/apps/meteor/ee/client/omnichannel/additionalForms/DepartmentForwarding.tsx
index ed9a40e4bd0e..a6760e66797b 100644
--- a/apps/meteor/ee/client/omnichannel/additionalForms/DepartmentForwarding.tsx
+++ b/apps/meteor/ee/client/omnichannel/additionalForms/DepartmentForwarding.tsx
@@ -1,4 +1,4 @@
-import { Field, Box, PaginatedMultiSelectFiltered } from '@rocket.chat/fuselage';
+import { Field, FieldLabel, FieldRow, FieldHint, Box, PaginatedMultiSelectFiltered } from '@rocket.chat/fuselage';
import type { PaginatedMultiSelectOption } from '@rocket.chat/fuselage';
import { useDebouncedValue } from '@rocket.chat/fuselage-hooks';
import type { TranslationKey } from '@rocket.chat/ui-contexts';
@@ -35,8 +35,8 @@ export const DepartmentForwarding = ({ departmentId, value = [], handler, label
return (
- {t(label)}
-
+ {t(label)}
+
-
- {t('List_of_departments_for_forward_description')}
+
+ {t('List_of_departments_for_forward_description')}
);
};
diff --git a/apps/meteor/ee/client/omnichannel/additionalForms/MaxChatsPerAgent.tsx b/apps/meteor/ee/client/omnichannel/additionalForms/MaxChatsPerAgent.tsx
index 924305e947fd..1894b1367c15 100644
--- a/apps/meteor/ee/client/omnichannel/additionalForms/MaxChatsPerAgent.tsx
+++ b/apps/meteor/ee/client/omnichannel/additionalForms/MaxChatsPerAgent.tsx
@@ -1,4 +1,4 @@
-import { NumberInput, Field } from '@rocket.chat/fuselage';
+import { NumberInput, Field, FieldLabel, FieldRow } from '@rocket.chat/fuselage';
import { useTranslation } from '@rocket.chat/ui-contexts';
import type { FC } from 'react';
import React from 'react';
@@ -13,10 +13,10 @@ const MaxChatsPerAgent: FC<{
return (
- {t('Max_number_of_chats_per_agent')}
-
+ {t('Max_number_of_chats_per_agent')}
+
-
+
);
};
diff --git a/apps/meteor/ee/client/omnichannel/additionalForms/PrioritiesSelect.tsx b/apps/meteor/ee/client/omnichannel/additionalForms/PrioritiesSelect.tsx
index 072123de21e0..d4cd920cfa9a 100644
--- a/apps/meteor/ee/client/omnichannel/additionalForms/PrioritiesSelect.tsx
+++ b/apps/meteor/ee/client/omnichannel/additionalForms/PrioritiesSelect.tsx
@@ -1,7 +1,7 @@
import type { ILivechatPriority, Serialized } from '@rocket.chat/core-typings';
import { LivechatPriorityWeight } from '@rocket.chat/core-typings';
import type { SelectOption } from '@rocket.chat/fuselage';
-import { Options, Box, Option, Field, SelectLegacy } from '@rocket.chat/fuselage';
+import { Options, Box, Option, Field, FieldLabel, FieldRow, SelectLegacy } from '@rocket.chat/fuselage';
import type { TranslationKey } from '@rocket.chat/ui-contexts';
import { useTranslation } from '@rocket.chat/ui-contexts';
import type { ComponentProps } from 'react';
@@ -47,8 +47,8 @@ export const PrioritiesSelect = ({ value = '', label, options, onChange }: Prior
return (
- {label}
-
+ {label}
+
{renderOption(label, value)}}
renderItem={({ label, value, ...props }) => }
/>
-
+
);
};
diff --git a/apps/meteor/ee/client/omnichannel/additionalForms/SlaPoliciesSelect.tsx b/apps/meteor/ee/client/omnichannel/additionalForms/SlaPoliciesSelect.tsx
index 61e2f9505268..5d90d0eda169 100644
--- a/apps/meteor/ee/client/omnichannel/additionalForms/SlaPoliciesSelect.tsx
+++ b/apps/meteor/ee/client/omnichannel/additionalForms/SlaPoliciesSelect.tsx
@@ -1,6 +1,6 @@
import type { IOmnichannelServiceLevelAgreements, Serialized } from '@rocket.chat/core-typings';
import type { SelectOption } from '@rocket.chat/fuselage';
-import { Field, Select } from '@rocket.chat/fuselage';
+import { Field, FieldLabel, FieldRow, Select } from '@rocket.chat/fuselage';
import React, { useMemo } from 'react';
type SlaPoliciesSelectProps = {
@@ -15,10 +15,10 @@ export const SlaPoliciesSelect = ({ value, label, options, onChange }: SlaPolici
return (
- {label}
-
+ {label}
+
+
);
};
diff --git a/apps/meteor/ee/client/omnichannel/cannedResponses/components/cannedResponseForm.tsx b/apps/meteor/ee/client/omnichannel/cannedResponses/components/cannedResponseForm.tsx
index 9560d61c28ae..5b9fb7433f7f 100644
--- a/apps/meteor/ee/client/omnichannel/cannedResponses/components/cannedResponseForm.tsx
+++ b/apps/meteor/ee/client/omnichannel/cannedResponses/components/cannedResponseForm.tsx
@@ -1,5 +1,5 @@
import { css } from '@rocket.chat/css-in-js';
-import { Box, Field, TextInput } from '@rocket.chat/fuselage';
+import { Box, Field, FieldLabel, FieldRow, FieldError, FieldDescription, TextInput } from '@rocket.chat/fuselage';
import { useTranslation } from '@rocket.chat/ui-contexts';
import type { FC } from 'react';
import React from 'react';
@@ -36,7 +36,7 @@ const CannedResponseForm: FC<{
return (
<>
- {t('Shortcut')}
+ {t('Shortcut')}
- {errors.shortcut}
+ {errors.shortcut}
-
+
{t('Message')}
{previewState ? t('Editor') : t('Preview')}
-
+
{previewState ? : }
@@ -63,21 +63,21 @@ const CannedResponseForm: FC<{
{(isManager || isMonitor) && (
<>
- {t('Sharing')}
- {radioDescription}
-
+ {t('Sharing')}
+ {radioDescription}
+
-
+
{scope === 'department' && (
- {t('Department')}
+ {t('Department')}
- {errors.departmentId}
+ {errors.departmentId}
)}
>
diff --git a/apps/meteor/ee/client/omnichannel/monitors/MonitorsTable.tsx b/apps/meteor/ee/client/omnichannel/monitors/MonitorsTable.tsx
index 3976e81e671c..b14e293b5d79 100644
--- a/apps/meteor/ee/client/omnichannel/monitors/MonitorsTable.tsx
+++ b/apps/meteor/ee/client/omnichannel/monitors/MonitorsTable.tsx
@@ -3,6 +3,8 @@ import {
Pagination,
Button,
Field,
+ FieldLabel,
+ FieldRow,
Box,
States,
StatesIcon,
@@ -125,13 +127,13 @@ const MonitorsTable = () => {
<>
- {t('Username')}
-
+ {t('Username')}
+
void} />
-
+
{((isSuccess && data?.monitors.length > 0) || queryHasChanged) && setText(text)} />}
diff --git a/apps/meteor/ee/client/omnichannel/priorities/PriorityEditForm.tsx b/apps/meteor/ee/client/omnichannel/priorities/PriorityEditForm.tsx
index 81d0fd72a2e6..042a6a7d2498 100644
--- a/apps/meteor/ee/client/omnichannel/priorities/PriorityEditForm.tsx
+++ b/apps/meteor/ee/client/omnichannel/priorities/PriorityEditForm.tsx
@@ -1,5 +1,5 @@
import type { ILivechatPriority, Serialized } from '@rocket.chat/core-typings';
-import { Field, Button, Box, ButtonGroup, Throbber } from '@rocket.chat/fuselage';
+import { Field, FieldError, Button, Box, ButtonGroup, Throbber } from '@rocket.chat/fuselage';
import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
import type { TranslationKey } from '@rocket.chat/ui-contexts';
import { useToastMessageDispatch, useTranslation } from '@rocket.chat/ui-contexts';
@@ -93,7 +93,7 @@ const PriorityEditForm = ({ data, onSave, onCancel }: PriorityEditFormProps): Re
/>
)}
/>
- {errors.name?.message}
+ {errors.name?.message}
diff --git a/apps/meteor/ee/client/omnichannel/slaPolicies/SlaEdit.tsx b/apps/meteor/ee/client/omnichannel/slaPolicies/SlaEdit.tsx
index 30bcd110a56e..83f2c4a36e72 100644
--- a/apps/meteor/ee/client/omnichannel/slaPolicies/SlaEdit.tsx
+++ b/apps/meteor/ee/client/omnichannel/slaPolicies/SlaEdit.tsx
@@ -1,5 +1,5 @@
import type { IOmnichannelServiceLevelAgreements, Serialized } from '@rocket.chat/core-typings';
-import { Field, TextInput, Button, Margins, Box, NumberInput } from '@rocket.chat/fuselage';
+import { Field, FieldLabel, FieldRow, FieldError, TextInput, Button, Margins, Box, NumberInput } from '@rocket.chat/fuselage';
import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
import { useToastMessageDispatch, useRoute, useTranslation, useEndpoint } from '@rocket.chat/ui-contexts';
import type { ReactElement } from 'react';
@@ -78,32 +78,32 @@ function SlaEdit({ data, isNew, slaId, reload, ...props }: SlaEditProps): ReactE
return (
- {t('Name')}*
-
+ {t('Name')}*
+
-
- {errors.name?.message}
+
+ {errors.name?.message}
- {t('Description')}
-
+ {t('Description')}
+
-
+
- {t('Estimated_wait_time_in_minutes')}*
-
+ {t('Estimated_wait_time_in_minutes')}*
+
-
- {errors.dueTimeInMinutes?.message}
+
+ {errors.dueTimeInMinutes?.message}
-
+
{!isNew && (
@@ -116,7 +116,7 @@ function SlaEdit({ data, isNew, slaId, reload, ...props }: SlaEditProps): ReactE
-
+
);
diff --git a/apps/meteor/ee/client/views/audit/components/AuditForm.tsx b/apps/meteor/ee/client/views/audit/components/AuditForm.tsx
index 3888013d8732..f8fbb63e3903 100644
--- a/apps/meteor/ee/client/views/audit/components/AuditForm.tsx
+++ b/apps/meteor/ee/client/views/audit/components/AuditForm.tsx
@@ -1,5 +1,5 @@
import type { IAuditLog } from '@rocket.chat/core-typings';
-import { Box, Field, TextInput, Button, ButtonGroup } from '@rocket.chat/fuselage';
+import { Box, Field, FieldLabel, FieldRow, FieldError, TextInput, Button, ButtonGroup } from '@rocket.chat/fuselage';
import { useTranslation } from '@rocket.chat/ui-contexts';
import React from 'react';
import { useController } from 'react-hook-form';
@@ -40,18 +40,18 @@ const AuditForm = ({ type, onSubmit }: AuditFormProps) => {
diff --git a/apps/meteor/ee/client/voip/modals/DeviceSettingsModal.tsx b/apps/meteor/ee/client/voip/modals/DeviceSettingsModal.tsx
index 4bda542fdb63..70202a42348b 100644
--- a/apps/meteor/ee/client/voip/modals/DeviceSettingsModal.tsx
+++ b/apps/meteor/ee/client/voip/modals/DeviceSettingsModal.tsx
@@ -1,5 +1,5 @@
import type { SelectOption } from '@rocket.chat/fuselage';
-import { Modal, Field, Select, Button, Box } from '@rocket.chat/fuselage';
+import { Modal, Field, FieldLabel, FieldRow, Select, Button, Box } from '@rocket.chat/fuselage';
import {
useTranslation,
useAvailableDevices,
@@ -77,8 +77,8 @@ const DeviceSettingsModal = (): ReactElement => {
)}
- {t('Microphone')}
-
+ {t('Microphone')}
+
{
)}
/>
-
+
- {t('Speakers')}
-
+ {t('Speakers')}
+
{
)}
/>
-
+
diff --git a/packages/fuselage-ui-kit/src/blocks/InputBlock.tsx b/packages/fuselage-ui-kit/src/blocks/InputBlock.tsx
index bbeaf3c338c6..979e04e808c7 100644
--- a/packages/fuselage-ui-kit/src/blocks/InputBlock.tsx
+++ b/packages/fuselage-ui-kit/src/blocks/InputBlock.tsx
@@ -1,4 +1,10 @@
-import { Field } from '@rocket.chat/fuselage';
+import {
+ Field,
+ FieldLabel,
+ FieldRow,
+ FieldError,
+ FieldHint,
+} from '@rocket.chat/fuselage';
import * as UiKit from '@rocket.chat/ui-kit';
import type { ReactElement } from 'react';
import { memo, useMemo } from 'react';
@@ -28,19 +34,19 @@ const InputBlock = ({
return (
{block.label && (
-
+
{surfaceRenderer.renderTextObject(
block.label,
0,
UiKit.BlockContext.NONE
)}
-
+
)}
-
+
{surfaceRenderer.renderInputBlockElement(inputElement, 0)}
-
- {error && {error}}
- {block.hint && {block.hint}}
+
+ {error && {error}}
+ {block.hint && {block.hint}}
);
};
diff --git a/packages/ui-client/src/components/CustomFieldsForm.tsx b/packages/ui-client/src/components/CustomFieldsForm.tsx
index 9423456ebe8e..0d1ba2ca5b1b 100644
--- a/packages/ui-client/src/components/CustomFieldsForm.tsx
+++ b/packages/ui-client/src/components/CustomFieldsForm.tsx
@@ -1,6 +1,6 @@
import type { CustomFieldMetadata } from '@rocket.chat/core-typings';
import type { SelectOption } from '@rocket.chat/fuselage';
-import { Field, Select, TextInput } from '@rocket.chat/fuselage';
+import { Field, FieldLabel, FieldRow, FieldError, Select, TextInput } from '@rocket.chat/fuselage';
import { useUniqueId } from '@rocket.chat/fuselage-hooks';
import type { TranslationKey } from '@rocket.chat/ui-contexts';
import { useTranslation } from '@rocket.chat/ui-contexts';
@@ -73,10 +73,10 @@ const CustomField = ({
rules={{ minLength: props.minLength, maxLength: props.maxLength, validate: { required: validateRequired } }}
render={({ field }) => (
-
+
{label || t(name as TranslationKey)}
-
-
+
+
({
options={selectOptions as SelectOption[]}
flexGrow={1}
/>
-
-
+
+
{errorMessage}
-
+
)}
/>
diff --git a/packages/web-ui-registration/src/EmailConfirmationForm.tsx b/packages/web-ui-registration/src/EmailConfirmationForm.tsx
index 6cd1331ef396..285181b6aa35 100644
--- a/packages/web-ui-registration/src/EmailConfirmationForm.tsx
+++ b/packages/web-ui-registration/src/EmailConfirmationForm.tsx
@@ -1,4 +1,4 @@
-import { FieldGroup, TextInput, Field, ButtonGroup, Button, Callout } from '@rocket.chat/fuselage';
+import { FieldGroup, TextInput, Field, FieldLabel, FieldRow, FieldError, ButtonGroup, Button, Callout } from '@rocket.chat/fuselage';
import { Form, ActionLink } from '@rocket.chat/layout';
import type { ReactElement } from 'react';
import { useForm } from 'react-hook-form';
@@ -39,8 +39,8 @@ export const EmailConfirmationForm = ({ email, onBackToLogin }: { email?: string
- {t('registration.component.form.email')}*
-
+ {t('registration.component.form.email')}*
+
-
- {errors.email && {t('registration.component.form.requiredField')}}
+
+ {errors.email && {t('registration.component.form.requiredField')}}
{sendEmail.isSuccess && (
diff --git a/packages/web-ui-registration/src/LoginForm.tsx b/packages/web-ui-registration/src/LoginForm.tsx
index efc7e6268feb..74f4bbec2185 100644
--- a/packages/web-ui-registration/src/LoginForm.tsx
+++ b/packages/web-ui-registration/src/LoginForm.tsx
@@ -1,4 +1,16 @@
-import { FieldGroup, TextInput, Field, PasswordInput, ButtonGroup, Button, Callout } from '@rocket.chat/fuselage';
+import {
+ FieldGroup,
+ TextInput,
+ Field,
+ FieldLabel,
+ FieldRow,
+ FieldError,
+ FieldLink,
+ PasswordInput,
+ ButtonGroup,
+ Button,
+ Callout,
+} from '@rocket.chat/fuselage';
import { useUniqueId } from '@rocket.chat/fuselage-hooks';
import { Form, ActionLink } from '@rocket.chat/layout';
import { useLoginWithPassword, useSetting } from '@rocket.chat/ui-contexts';
@@ -122,10 +134,10 @@ export const LoginForm = ({ setLoginRoute }: { setLoginRoute: DispatchLoginRoute
-
+
{t('registration.component.form.emailOrUsername')}
-
-
+
+
-
+
{errors.username && (
-
+
{errors.username.message}
-
+
)}
-
+
{t('registration.component.form.password')}
-
-
+
+
-
+
{errors.password && (
-
+
{errors.password.message}
-
+
)}
{isResetPasswordAllowed && (
-
-
+ {
e.preventDefault();
@@ -174,8 +186,8 @@ export const LoginForm = ({ setLoginRoute }: { setLoginRoute: DispatchLoginRoute
}}
>
Forgot your password?
-
-
+
+
)}
diff --git a/packages/web-ui-registration/src/RegisterForm.tsx b/packages/web-ui-registration/src/RegisterForm.tsx
index 6202916c87f2..df327f05ed61 100644
--- a/packages/web-ui-registration/src/RegisterForm.tsx
+++ b/packages/web-ui-registration/src/RegisterForm.tsx
@@ -1,5 +1,17 @@
/* eslint-disable complexity */
-import { FieldGroup, TextInput, Field, PasswordInput, ButtonGroup, Button, TextAreaInput, Callout } from '@rocket.chat/fuselage';
+import {
+ FieldGroup,
+ TextInput,
+ Field,
+ FieldLabel,
+ FieldRow,
+ FieldError,
+ PasswordInput,
+ ButtonGroup,
+ Button,
+ TextAreaInput,
+ Callout,
+} from '@rocket.chat/fuselage';
import { useUniqueId } from '@rocket.chat/fuselage-hooks';
import { Form, ActionLink } from '@rocket.chat/layout';
import { CustomFieldsForm, PasswordVerifier, useValidatePassword } from '@rocket.chat/ui-client';
@@ -123,10 +135,10 @@ export const RegisterForm = ({ setLoginRoute }: { setLoginRoute: DispatchLoginRo
-
+
{t('registration.component.form.name')}
-
-
+
+
-
+
{errors.name && (
-
+
{errors.name.message}
-
+
)}
-
+
{t('registration.component.form.email')}
-
-
+
+
-
+
{errors.email && (
-
+
{errors.email.message}
-
+
)}
-
+
{t('registration.component.form.username')}
-
-
+
+
-
+
{errors.username && (
-
+
{errors.username.message}
-
+
)}
-
+
{t('registration.component.form.password')}
-
-
+
+
-
+
{errors?.password && (
-
+
{errors.password.message}
-
+
)}
{requiresPasswordConfirmation && (
-
+
{t('registration.component.form.confirmPassword')}
-
-
+
+
-
+
{errors.passwordConfirmation && (
-
+
{errors.passwordConfirmation.message}
-
+
)}
)}
{manuallyApproveNewUsersRequired && (
-
+
{t('registration.component.form.reasonToJoin')}
-
-
+
+
-
+
{errors.reason && (
-
+
{errors.reason.message}
-
+
)}
)}
diff --git a/packages/web-ui-registration/src/template/FormSkeleton.tsx b/packages/web-ui-registration/src/template/FormSkeleton.tsx
index 44f073258fe6..31425a0847f2 100644
--- a/packages/web-ui-registration/src/template/FormSkeleton.tsx
+++ b/packages/web-ui-registration/src/template/FormSkeleton.tsx
@@ -1,4 +1,4 @@
-import { Field, InputBox, Skeleton } from '@rocket.chat/fuselage';
+import { Field, FieldLabel, FieldRow, FieldHint, FieldDescription, InputBox, Skeleton } from '@rocket.chat/fuselage';
import { Form } from '@rocket.chat/layout';
import type { ReactElement } from 'react';
@@ -12,18 +12,18 @@ const FormSkeleton = (): ReactElement => {
-
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
From abfb6b38119bea0d1b5df065bad5f0e0c70d0d8c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=BAlia=20Jaeger=20Foresti?=
<60678893+juliajforesti@users.noreply.github.com>
Date: Wed, 4 Oct 2023 16:31:31 -0300
Subject: [PATCH 31/35] chore: `AccessibilityPage` hide Enterprise tag when is
EE (#30486)
Co-authored-by: Guilherme Gazzo <5263975+ggazzo@users.noreply.github.com>
---
.../accessibility/AccessibilityPage.tsx | 25 +++++++++++--------
1 file changed, 14 insertions(+), 11 deletions(-)
diff --git a/apps/meteor/client/views/account/accessibility/AccessibilityPage.tsx b/apps/meteor/client/views/account/accessibility/AccessibilityPage.tsx
index ceb904613533..657548d5a1b9 100644
--- a/apps/meteor/client/views/account/accessibility/AccessibilityPage.tsx
+++ b/apps/meteor/client/views/account/accessibility/AccessibilityPage.tsx
@@ -38,8 +38,9 @@ const AccessibilityPage = () => {
const t = useTranslation();
const setModal = useSetModal();
const dispatchToastMessage = useToastMessageDispatch();
- const { data: license } = useIsEnterprise();
const preferencesValues = useAccessiblityPreferencesValues();
+ const { data: license } = useIsEnterprise();
+ const isEnterprise = license?.isEnterprise;
const { themeAppearence } = preferencesValues;
const [, setPrevTheme] = useLocalStorage('prevTheme', themeAppearence);
@@ -102,14 +103,14 @@ const AccessibilityPage = () => {
{themes.map(({ id, title, description, ...item }, index) => {
- const communityDisabled = 'isEEOnly' in item && item.isEEOnly && !license?.isEnterprise;
+ const showCommunityUpsellTriggers = 'isEEOnly' in item && item.isEEOnly && !isEnterprise;
return (
{t.has(title) ? t(title) : title}
- {communityDisabled && (
+ {showCommunityUpsellTriggers && (
@@ -123,7 +124,7 @@ const AccessibilityPage = () => {
control={control}
name='themeAppearence'
render={({ field: { onChange, value, ref } }) => {
- if (communityDisabled) {
+ if (showCommunityUpsellTriggers) {
return (
{
{t('Mentions_with_@_symbol')}
-
-
-
- {t('Enterprise')}
-
-
+ {!isEnterprise && (
+
+
+
+ {t('Enterprise')}
+
+
+ )}
- {license?.isEnterprise ? (
+ {isEnterprise ? (
Date: Wed, 4 Oct 2023 17:29:43 -0300
Subject: [PATCH 32/35] chore: anchor text-decoration rules (#30485)
Co-authored-by: Douglas Fabris <27704687+dougfabris@users.noreply.github.com>
---
.../app/theme/client/imports/general/base.css | 6 ----
apps/meteor/client/sidebar/Sidebar.tsx | 3 ++
.../PreferencesMessagesSection.tsx | 30 ++++---------------
apps/meteor/package.json | 2 +-
ee/packages/ui-theming/package.json | 2 +-
packages/fuselage-ui-kit/package.json | 2 +-
packages/gazzodown/package.json | 2 +-
packages/ui-client/package.json | 2 +-
packages/ui-composer/package.json | 2 +-
packages/ui-video-conf/package.json | 2 +-
packages/uikit-playground/package.json | 2 +-
yarn.lock | 24 +++++++--------
12 files changed, 28 insertions(+), 51 deletions(-)
diff --git a/apps/meteor/app/theme/client/imports/general/base.css b/apps/meteor/app/theme/client/imports/general/base.css
index 311327fb6f73..d1f4b8d11fb6 100644
--- a/apps/meteor/app/theme/client/imports/general/base.css
+++ b/apps/meteor/app/theme/client/imports/general/base.css
@@ -52,12 +52,6 @@ body {
a {
cursor: pointer;
- text-decoration: none;
-
- &:hover,
- &:active {
- text-decoration: none;
- }
}
button {
diff --git a/apps/meteor/client/sidebar/Sidebar.tsx b/apps/meteor/client/sidebar/Sidebar.tsx
index 9c7634872ed4..84c63eac01be 100644
--- a/apps/meteor/client/sidebar/Sidebar.tsx
+++ b/apps/meteor/client/sidebar/Sidebar.tsx
@@ -22,6 +22,9 @@ const Sidebar = () => {
const sideBarBackground = css`
background-color: ${Palette.surface['surface-tint']};
+ a {
+ text-decoration: none;
+ }
`;
return (
diff --git a/apps/meteor/client/views/account/preferences/PreferencesMessagesSection.tsx b/apps/meteor/client/views/account/preferences/PreferencesMessagesSection.tsx
index 1c93126b0345..3edfabf23ac5 100644
--- a/apps/meteor/client/views/account/preferences/PreferencesMessagesSection.tsx
+++ b/apps/meteor/client/views/account/preferences/PreferencesMessagesSection.tsx
@@ -1,27 +1,13 @@
import type { SelectOption } from '@rocket.chat/fuselage';
-import {
- Field,
- FieldRow,
- FieldDescription,
- FieldLabel,
- FieldGroup,
- FieldHint,
- Accordion,
- Select,
- ToggleSwitch,
- Box,
-} from '@rocket.chat/fuselage';
+import { FieldRow, FieldLink, FieldHint, FieldLabel, Accordion, Field, Select, FieldGroup, ToggleSwitch, Box } from '@rocket.chat/fuselage';
import { useUniqueId } from '@rocket.chat/fuselage-hooks';
-import { useRouter, useTranslation } from '@rocket.chat/ui-contexts';
+import { useTranslation } from '@rocket.chat/ui-contexts';
import React, { useMemo } from 'react';
import { Controller, useFormContext } from 'react-hook-form';
const PreferencesMessagesSection = () => {
const t = useTranslation();
const { control } = useFormContext();
- const router = useRouter();
-
- const handleGoToAccessibilityPage = () => router.navigate('/account/accessibility-and-appearance');
const alsoSendThreadMessageToChannelOptions = useMemo(
(): SelectOption[] => [
@@ -116,9 +102,7 @@ const PreferencesMessagesSection = () => {
{t('Message_TimeFormat')}
-
- {t('Go_to_accessibility_and_appearance')}
-
+ {t('Go_to_accessibility_and_appearance')}
@@ -192,15 +176,11 @@ const PreferencesMessagesSection = () => {
{t('Hide_usernames')}
-
- {t('Go_to_accessibility_and_appearance')}
-
+ {t('Go_to_accessibility_and_appearance')}
{t('Hide_roles')}
-
- {t('Go_to_accessibility_and_appearance')}
-
+ {t('Go_to_accessibility_and_appearance')}
diff --git a/apps/meteor/package.json b/apps/meteor/package.json
index 8bf3e3fe886a..c1014a749158 100644
--- a/apps/meteor/package.json
+++ b/apps/meteor/package.json
@@ -236,7 +236,7 @@
"@rocket.chat/favicon": "workspace:^",
"@rocket.chat/forked-matrix-appservice-bridge": "^4.0.1",
"@rocket.chat/forked-matrix-bot-sdk": "^0.6.0-beta.2",
- "@rocket.chat/fuselage": "^0.32.1",
+ "@rocket.chat/fuselage": "^0.32.2",
"@rocket.chat/fuselage-hooks": "^0.32.1",
"@rocket.chat/fuselage-polyfills": "next",
"@rocket.chat/fuselage-toastbar": "next",
diff --git a/ee/packages/ui-theming/package.json b/ee/packages/ui-theming/package.json
index a378fee8f896..f15c94365c06 100644
--- a/ee/packages/ui-theming/package.json
+++ b/ee/packages/ui-theming/package.json
@@ -4,7 +4,7 @@
"private": true,
"devDependencies": {
"@rocket.chat/css-in-js": "next",
- "@rocket.chat/fuselage": "^0.32.1",
+ "@rocket.chat/fuselage": "^0.32.2",
"@rocket.chat/fuselage-hooks": "^0.32.1",
"@rocket.chat/icons": "^0.32.0",
"@rocket.chat/ui-contexts": "workspace:~",
diff --git a/packages/fuselage-ui-kit/package.json b/packages/fuselage-ui-kit/package.json
index a376275d3b90..af89df400371 100644
--- a/packages/fuselage-ui-kit/package.json
+++ b/packages/fuselage-ui-kit/package.json
@@ -56,7 +56,7 @@
"devDependencies": {
"@rocket.chat/apps-engine": "1.41.0-alpha.290",
"@rocket.chat/eslint-config": "workspace:^",
- "@rocket.chat/fuselage": "^0.32.1",
+ "@rocket.chat/fuselage": "^0.32.2",
"@rocket.chat/fuselage-hooks": "^0.32.1",
"@rocket.chat/fuselage-polyfills": "next",
"@rocket.chat/icons": "^0.32.0",
diff --git a/packages/gazzodown/package.json b/packages/gazzodown/package.json
index 1b57545091f0..bf46cd4592ce 100644
--- a/packages/gazzodown/package.json
+++ b/packages/gazzodown/package.json
@@ -6,7 +6,7 @@
"@babel/core": "~7.22.9",
"@rocket.chat/core-typings": "workspace:^",
"@rocket.chat/css-in-js": "next",
- "@rocket.chat/fuselage": "^0.32.1",
+ "@rocket.chat/fuselage": "^0.32.2",
"@rocket.chat/fuselage-tokens": "next",
"@rocket.chat/message-parser": "next",
"@rocket.chat/styled": "next",
diff --git a/packages/ui-client/package.json b/packages/ui-client/package.json
index ce183b859e06..7df166d9e283 100644
--- a/packages/ui-client/package.json
+++ b/packages/ui-client/package.json
@@ -5,7 +5,7 @@
"devDependencies": {
"@babel/core": "~7.22.9",
"@rocket.chat/css-in-js": "next",
- "@rocket.chat/fuselage": "^0.32.1",
+ "@rocket.chat/fuselage": "^0.32.2",
"@rocket.chat/fuselage-hooks": "^0.32.1",
"@rocket.chat/icons": "^0.32.0",
"@rocket.chat/mock-providers": "workspace:^",
diff --git a/packages/ui-composer/package.json b/packages/ui-composer/package.json
index abf79394f171..1d5d478e17cd 100644
--- a/packages/ui-composer/package.json
+++ b/packages/ui-composer/package.json
@@ -5,7 +5,7 @@
"devDependencies": {
"@babel/core": "~7.22.9",
"@rocket.chat/eslint-config": "workspace:^",
- "@rocket.chat/fuselage": "^0.32.1",
+ "@rocket.chat/fuselage": "^0.32.2",
"@rocket.chat/icons": "^0.32.0",
"@storybook/addon-actions": "~6.5.16",
"@storybook/addon-docs": "~6.5.16",
diff --git a/packages/ui-video-conf/package.json b/packages/ui-video-conf/package.json
index ded2331aa09e..122a6a367903 100644
--- a/packages/ui-video-conf/package.json
+++ b/packages/ui-video-conf/package.json
@@ -6,7 +6,7 @@
"@babel/core": "~7.22.9",
"@rocket.chat/css-in-js": "next",
"@rocket.chat/eslint-config": "workspace:^",
- "@rocket.chat/fuselage": "^0.32.1",
+ "@rocket.chat/fuselage": "^0.32.2",
"@rocket.chat/fuselage-hooks": "^0.32.1",
"@rocket.chat/icons": "^0.32.0",
"@rocket.chat/styled": "next",
diff --git a/packages/uikit-playground/package.json b/packages/uikit-playground/package.json
index eb69dc5e017c..a0e43c570f31 100644
--- a/packages/uikit-playground/package.json
+++ b/packages/uikit-playground/package.json
@@ -15,7 +15,7 @@
"@codemirror/tooltip": "^0.19.16",
"@lezer/highlight": "^1.1.6",
"@rocket.chat/css-in-js": "next",
- "@rocket.chat/fuselage": "^0.32.1",
+ "@rocket.chat/fuselage": "^0.32.2",
"@rocket.chat/fuselage-hooks": "^0.32.1",
"@rocket.chat/fuselage-polyfills": "next",
"@rocket.chat/fuselage-tokens": "next",
diff --git a/yarn.lock b/yarn.lock
index b915bb0f2e2a..a25d91c4dd3c 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -8273,7 +8273,7 @@ __metadata:
dependencies:
"@rocket.chat/apps-engine": 1.41.0-alpha.290
"@rocket.chat/eslint-config": "workspace:^"
- "@rocket.chat/fuselage": ^0.32.1
+ "@rocket.chat/fuselage": ^0.32.2
"@rocket.chat/fuselage-hooks": ^0.32.1
"@rocket.chat/fuselage-polyfills": next
"@rocket.chat/gazzodown": "workspace:^"
@@ -8322,9 +8322,9 @@ __metadata:
languageName: unknown
linkType: soft
-"@rocket.chat/fuselage@npm:^0.32.1":
- version: 0.32.1
- resolution: "@rocket.chat/fuselage@npm:0.32.1"
+"@rocket.chat/fuselage@npm:^0.32.2":
+ version: 0.32.2
+ resolution: "@rocket.chat/fuselage@npm:0.32.2"
dependencies:
"@rocket.chat/css-in-js": ^0.31.25
"@rocket.chat/css-supports": ^0.31.25
@@ -8342,7 +8342,7 @@ __metadata:
react: ^17.0.2
react-dom: ^17.0.2
react-virtuoso: 1.2.4
- checksum: d3937be369a4b8e0d9849f5131a0143defcc313a38c2f4055a4d9bf2be6234c09244e71fde6c0adc90fbdfac8a0d572122e5fbbdac5c83656ac27063042ec94c
+ checksum: 28e80385961b090c71d0897c22c3c799ca05d30285456d96d3ca5ff2a1a4ba02362644084e611bd3f2a376acdf4c2e75180b8aee196a63969a7d6559abd73d79
languageName: node
linkType: hard
@@ -8353,7 +8353,7 @@ __metadata:
"@babel/core": ~7.22.9
"@rocket.chat/core-typings": "workspace:^"
"@rocket.chat/css-in-js": next
- "@rocket.chat/fuselage": ^0.32.1
+ "@rocket.chat/fuselage": ^0.32.2
"@rocket.chat/fuselage-tokens": next
"@rocket.chat/message-parser": next
"@rocket.chat/styled": next
@@ -8705,7 +8705,7 @@ __metadata:
"@rocket.chat/favicon": "workspace:^"
"@rocket.chat/forked-matrix-appservice-bridge": ^4.0.1
"@rocket.chat/forked-matrix-bot-sdk": ^0.6.0-beta.2
- "@rocket.chat/fuselage": ^0.32.1
+ "@rocket.chat/fuselage": ^0.32.2
"@rocket.chat/fuselage-hooks": ^0.32.1
"@rocket.chat/fuselage-polyfills": next
"@rocket.chat/fuselage-toastbar": next
@@ -9568,7 +9568,7 @@ __metadata:
dependencies:
"@babel/core": ~7.22.9
"@rocket.chat/css-in-js": next
- "@rocket.chat/fuselage": ^0.32.1
+ "@rocket.chat/fuselage": ^0.32.2
"@rocket.chat/fuselage-hooks": ^0.32.1
"@rocket.chat/icons": ^0.32.0
"@rocket.chat/mock-providers": "workspace:^"
@@ -9619,7 +9619,7 @@ __metadata:
dependencies:
"@babel/core": ~7.22.9
"@rocket.chat/eslint-config": "workspace:^"
- "@rocket.chat/fuselage": ^0.32.1
+ "@rocket.chat/fuselage": ^0.32.2
"@rocket.chat/icons": ^0.32.0
"@storybook/addon-actions": ~6.5.16
"@storybook/addon-docs": ~6.5.16
@@ -9690,7 +9690,7 @@ __metadata:
resolution: "@rocket.chat/ui-theming@workspace:ee/packages/ui-theming"
dependencies:
"@rocket.chat/css-in-js": next
- "@rocket.chat/fuselage": ^0.32.1
+ "@rocket.chat/fuselage": ^0.32.2
"@rocket.chat/fuselage-hooks": ^0.32.1
"@rocket.chat/icons": ^0.32.0
"@rocket.chat/ui-contexts": "workspace:~"
@@ -9733,7 +9733,7 @@ __metadata:
"@rocket.chat/css-in-js": next
"@rocket.chat/emitter": next
"@rocket.chat/eslint-config": "workspace:^"
- "@rocket.chat/fuselage": ^0.32.1
+ "@rocket.chat/fuselage": ^0.32.2
"@rocket.chat/fuselage-hooks": ^0.32.1
"@rocket.chat/icons": ^0.32.0
"@rocket.chat/styled": next
@@ -9776,7 +9776,7 @@ __metadata:
"@codemirror/tooltip": ^0.19.16
"@lezer/highlight": ^1.1.6
"@rocket.chat/css-in-js": next
- "@rocket.chat/fuselage": ^0.32.1
+ "@rocket.chat/fuselage": ^0.32.2
"@rocket.chat/fuselage-hooks": ^0.32.1
"@rocket.chat/fuselage-polyfills": next
"@rocket.chat/fuselage-tokens": next
From 8e89b5a3b0cc49f04134814ae0d3466719b31b2b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=BAlia=20Jaeger=20Foresti?=
<60678893+juliajforesti@users.noreply.github.com>
Date: Wed, 4 Oct 2023 18:58:27 -0300
Subject: [PATCH 33/35] fix: font-disabled color (#30569)
---
.changeset/tiny-wolves-deliver.md | 5 +++++
ee/packages/ui-theming/src/palette.ts | 2 +-
2 files changed, 6 insertions(+), 1 deletion(-)
create mode 100644 .changeset/tiny-wolves-deliver.md
diff --git a/.changeset/tiny-wolves-deliver.md b/.changeset/tiny-wolves-deliver.md
new file mode 100644
index 000000000000..f89564a9b53c
--- /dev/null
+++ b/.changeset/tiny-wolves-deliver.md
@@ -0,0 +1,5 @@
+---
+'@rocket.chat/ui-theming': patch
+---
+
+fix: light-theme font-disabled color
diff --git a/ee/packages/ui-theming/src/palette.ts b/ee/packages/ui-theming/src/palette.ts
index 4825beec0cff..39f8d3f2bfed 100644
--- a/ee/packages/ui-theming/src/palette.ts
+++ b/ee/packages/ui-theming/src/palette.ts
@@ -44,7 +44,7 @@ export const palette = [
description: 'These should be applied according to surfaces',
list: [
{ name: 'font-white', token: 'white', color: '#FFFFFF' },
- { name: 'font-disabled', token: 'N100', color: '#F7F8FA' },
+ { name: 'font-disabled', token: 'N500', color: '#CBCED1' },
{ name: 'font-annotation', token: 'N600', color: '#9EA2A8' },
{ name: 'font-hint', token: 'N700', color: '#6C727A' },
{ name: 'font-secondary-info', token: 'N700', color: '#6C727A' },
From 9aee190be8dc3935359b43ac62b6a8347ed642b4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=BAlia=20Jaeger=20Foresti?=
<60678893+juliajforesti@users.noreply.github.com>
Date: Wed, 4 Oct 2023 19:51:21 -0300
Subject: [PATCH 34/35] chore: update mentions upsell modal content (#30503)
---
.../MentionsWithSymbolUpsellModal.tsx | 13 ++++++-------
.../packages/rocketchat-i18n/i18n/en.i18n.json | 7 +++----
.../public/images/mentions-upsell-modal.png | Bin 0 -> 9723 bytes
3 files changed, 9 insertions(+), 11 deletions(-)
create mode 100644 apps/meteor/public/images/mentions-upsell-modal.png
diff --git a/apps/meteor/client/views/account/accessibility/MentionsWithSymbolUpsellModal.tsx b/apps/meteor/client/views/account/accessibility/MentionsWithSymbolUpsellModal.tsx
index 8a998af348c0..b92ca74d0f6e 100644
--- a/apps/meteor/client/views/account/accessibility/MentionsWithSymbolUpsellModal.tsx
+++ b/apps/meteor/client/views/account/accessibility/MentionsWithSymbolUpsellModal.tsx
@@ -13,22 +13,21 @@ const MentionsWithSymbolUpsellModal = ({ onClose }: { onClose: () => void }) =>
if (!isAdmin) {
return (
);
}
return (
mZSyQpA^bk*|Me*(Gaq)W#6(6S!R$2l|3>s_O-0p34=tq$MgP<-@oti{xQcK_cix*-`90spYuFF=jWVf_Y8G8+4$K20N}i%
zcgq9-jyM7U1Hj5mA2}V;&rAP0=BH;B2mtJ-4nGV)b`BqXkRi}S_XbciEVx9!U~hXO4jsqYOB=VW0t-1b`VwIP&9Wkm
z%S^AGP3b+eEqM~V{c#WCuPxYjvUE>@Kk4Hc6z1-yZ5Q+FMxKBzz>{F35YtNd-$D;hi1&pQ|AHTI+9tL&7=})cecN(UUGV&us(F*(O7r@4tjs?8^!(X
z80jx0Cog@Cp94SOZ&Y!dPCkg7x-m(kV&e~7zt>R9-ukadCi(PZ4UP7(Z8&dt4I`Z^XK=COacXFGS}
z?8DQ)xA5OH<#}NZe$|1O43aqnLLcq_xi>*bVE@N^FNIcM<$Ilur=3lr&3bRskHH!l
z*|o{{pJfdpbYm&;Zh!ySb9B~6_aCe9MztwzeJoAWK8s#^Mmno$U;Kc+rF;V~X(?WN
zk=xow0DzDvt_J{7dE8M9^b2o4hHuVSxM8hIY$own+LfMo{hD1AMQ`N<7K?rfjG-?&
zaJ6APR$aLj7_83H|DI!X+ZO&o@B8}>s}H()0-E>*hWVYdg4v?2m&Yg#$BWE7JT%dGe-V$Ypv=81CCi@hOim=_B?>jZ
zZsxJXLJAF&^DpF31bI#T04stFQrZJ>{hl7L3T-V=jfMd(&=-%8WhJlgO3C=n6DaP>
zU?G+2h_k;)@6M%9L}X?9&U7_2il-;cZV(9PVG}`TP9^pgn^DIa3707j*p_V%P&u!|
zBSS-3d)?{0(ozx$(Q;SH9+KyEP(1qZ?URLkas-5kWavyuXna3T>YIDz{?eR}d0_R6
zj`dOvW?QAzaNpW*D+?Q(9j*8_&;?>JCD{$09wYpu2ZLDWhy9Rd+e_Q(n
zo_VNO9Y5(-$sYR1kKvWg)t9Z;@)KK?;?r7VLmT2!)RiNKhZsLCUsX}~?HS&F#iC8W
z&@T%IFC~oGS-qb44hl1pmFa;0p8)u(od2U2mjJ*qLB-Hnb*kFR9xe(#T{0x5cIY^7
z^-eH7RQuyRw+};Y)!h3n3noVZ=)QE7r7YmD-{v{XKu<+)pR+GpUtyyMKTDU>lOl+F
zjE9l=>Jj<>4g-~ol6qx@bgM3=u~$l-{2dt*0S@|v3miw5%Zo%0A7;J@A${Qe_pDpS
zA0-cCiKdRfbn~C{`13;j+3OM!JoEI|m>+v`-CLKFzKZL}*9?q;A;H1oB9Z&2wj!zP
zrb|d(roN?Nwe?i4>BxNY&y+3;V9G^I)F&@-+`!iI-m&X%-0~@LWCF{YGL7-qgpGq#
z7jf~!LZl<>oJ!h~Hv)B;o}O+$&;ytqU#(HoLbxM-oa97k?&WKWp=<0;&5k510>xZ>
zv#*V4yYoyAlBL8O@KOdF4B~i6(cy3k?Lh3v{ZY;6sOrYufnYick`I&4|-caVAM|*9K-GfTOWT&)y+>|#K^JTdSZh;-{Z4>V*TfB
z4=F?J-$kFPu^tQsvbzZR%6&;uyU?1I(1B6IQb`F{1kSb1KpN*Iq
z;(a~pE{zRY_WDU6JZECiIOSa;C9J+jb|_;Y-UraJ+K!a_r#nzZO+HPp8x(+>ZHr4<
zsbvcLt3~|wF||{^B!;#haRRIe>9X{S8R!&NzE)yZ7287Vd>&%M@my&jR6_Y!^Ku2t
zN3TajFDCnB)-h{_>Mu;*MGoij+ik=z2}SNr8Z?)y$@AmE(-OX#Ddt+s9=(;TFqE}7
z(n4I?I;3daC{H-u$H8cMj&B-&PUa#gL0nHTgW0xNxy$JN)QqhCLAZEUM~0FO^vl;1
z#xczf(z^4RD3mFKcah997e(vIkCqdIucv}GjIFMg96w&Es%vJAd9$5jksD5Q*Rft;
z3+TclR}JbK6d3r9yONvp(>84)U3WqPc011F<+8983z{Q;M&}1I6LwELi%gZP6=u8#
z^6CNFAD1#%nq76`A!i)DW7g-bUwLVy!f;?JHS?=x9KgYn#)WWoAZIKk)->6N7K^;=
zTj4FEg`*MZ#1iSPE<8)GTIXoc7P@S}`&MDFpK^+v*Z7Ms1LBZrhpyO<*aK98LL+8-
zp%>cQbHv5N+(%9gW^Y5TuC;ro40QX80XNsl>ur!T5g_OuY)t%<#9)WzkJWYgDFv11
zNQ4Kpi@MJkfa~PSwwCAoT)&`qHTDAu>N4(~_Xw`Bpw1h;5|wTj)|fG3ROJ)|WqVwA9V5^A
z9s>$GyQ2;FnH(2$Cp<6a=G};?eQ4^O$E<<(NG;R8_lmuHs|UvHJ+lP5G9#ZG!)$es
zUi++nOrA272fYFzCoTALRw=k=D+?B?ghBWp=Sq9x2szfKWu~BySSmltAGpq9>+UH*
z-)y4;EV~Sp!e8LrW1(b|IVVfiC+X=}Pe9GeG`FP42>q`hi7Hj_M}c0Y|T5c4(K4j?G^FZ)xG
z@7NIc-*OyDP_%2%IzUz~69S8`gcKGlH$Wd8bmdLuY?H8(K-BKLY?jSb*6tCh)r?1X
z>qnDY;IstAo0|zp10mut;R|u#CFzWajSS6nMG&j)Mx1NvlY^Q9z;xD`1)82EH&e
zj=x_>t6-FfzqU4=59;4E_5V~GVW~xcJRNjnuw>IpajjLx%%kS~1ZN>k(?uivkpx(u&(uJA*
zevZMqk=k}GcF(}IyZc0Lem)#5`h(dnL%?rZvQaCdkeQ=%Ky?7#Eyek`hBkqO8}9R$
zNN0*36y-$jM(Y$bd;daZZEWYRNYLhCDAA>2R|n3rpz}W!rp-%0Nv?5}FF5Lhu;ZLR
z>$ewEvc#l2^T;KYMB^9Ysrty$o`O4jD*+Boi&=76kb3dHdWHC(7`HBMnO9;#GVS>M
za^zo*jOz!)uWJvOR8*?jG|yT@3Vbng^xQS_YOa~t6G*t$I#zHCPn-mYG5g4VMVOB^
zI9SUVmo(jXNiW;Q#WgY;t$WmnU84=?dI`<*dQyYAd!G%ujtd#D?-zE-fRl8^+HjdR
zKPMG=ZnUH^+vD+Qki16jkf+EV-Y8Nh>LyC3s{ATRZG8Q?xE{gKtGMyDB%IYOMx68G
zIlFrN3S9g;sx)4qd(66ej&Sl|{|x8s7_A{|89ayDgkxLuA~D`i4+u9&%Sd%Gz>!ht
zs8usx3y8Jb@5H3wUcVUaqcmp*=(+VumrM4B{%rwIpnNE0l0ggJ2HmmDu90RE5}@D|
zzFkZ&hpeZXFHy>N&ZbP45kEF>LgXlgtc)s}vK@PyYe}C7Q+<*g=UJ89#DsDmALOwJ
z)K)K^%iWs$sS7Ox`>C=~`jv}XzJpc;aRxt?ACGTIoezeMlP9W=OkjTO#E(9E
zc<^pX(rCSelEHOAPSK4%|4gn|^NlZL*={SgJnv+|VEkH_5n!|QJ@x>HT5#2q^M4@8
z5M?ktZ2uyhI+_A+D~#%}@r6`JQ1@t+z|9e7VfkEDUAGS{*8qB1>6c+xaR5)z^w#u_
zPF!Fa;suT;@XOD#MjW(=zz#{q)=MpF#jFZtx@$X=fUjv>+Kln=gMy+8-Ax#8(`z@5
zRHb$*o#tS_k+a8{jBm0EPSnZj+@k-2_hzqQMF4{QbS5WZcGOCha-@gXQQ4=Xp_3s6
z;D~Cd7hRcN4=X3ykhHlY7>5&Y=pwg6%qYzp%Rn
zQ0t676D34=Z9i67Q)<4dpVmoCGRf|0^k&usAGItm7Uf;n=0W})
zNr}+EqwADS>??jd&Qb@R6}+_HzX&Hwa+F-;L1TS%zz$2KSy8Q)
z1dwcWTBnR>kd7@ng^uCwSW^r@InlJAG%gqnqK%rBZ_=qbU!wH>^DZi9DA7&JL{;CUJiPTs56fNA;MHgGxY(|}
zbdRWD@p2Jr!M;aQ7PA*xB+R*~i`lcd9s3Z9CVmQPEW+eHLiJ@R`3$4Vh9cz4m%O&!
zE_be|t3GwyQlr@c1;-8-SkPo`wXrkTNxT1|;cDAff|f-2dSq>=EeYC-RG0WM9r8tr
zOZ^qIw(^}<%=awDq8499k}6M@L}xMU^2>V^lxkchOS&(2c)N5x(b4
zJhG$cWIY8cG{enxC&~%(Y1Q$Rt0dtEzfxrXe{qBnpii$kM*PDmb{7BP)hsV)%$sC
z?|7HFf>3D&jJ-=0%x79ck$=LDh8
zo3xc*HD;9)GD?$TXJX)h84h}pes&y!sLw%(@%F&+?W~`%FePD_;!S4X)(>BwyU?>;
z3S@T-VdZ0G%rnTqCu^5Db%?s-ve&}>SJ&OG1kUhy7B|XS-e$b8%2At(Z%9j;U)u9X&QXTfZbyPqjr!
zP~je$UyYN>c%-X|Y-5vE(gpmT6qyBG5W5(6lP@fI0+}tstBpB#9pwn(Wk74XW;Zi?
zZ8wH)DWKPv!zRDJsdrKsY2S3}a=!f_udHwMj>w{YbD1CXQEkN4;^0=K>h!YGw3hww
z(aiP4dvv-E
z6L)cA3p$){2mR%8N=cfHnG?h-z`&8xFHR}78Z|=eO)0Nv@6i3@EVS`SCp2o?H5z89
z;lD-QdqoK{l&6epGho0+7UP%|R2w?`Ssb@*uR1}$7Bkzca_aCjE;-Q|w2t)y+3MG+
znbIizfS&x8%n5an6npJ^d1(z@>bn=`?Mrc?(1TYNVRtim=s?gO8GWkk31l)GO~Rz$
zPZgK%)pmLLzzok620}f`!>X&Fvr|42e0^>Yrc?}~9M@ypBhPWZo@vW=y6c5em>n=8
zSCEz#^*C9Z7Gw^#M9T5uU%yt#Oq4|E(}Bt`=&tatvC|tqRv;lFSuJvEtx9uh^~Lh+(PNJH5O8LTLq`IwX6zEj5Vjca
z{Y`ZK)!fB$Bj}GYfAJ0L-N13EwOl97Av^m@YtPy>Nr*-n?OhA<+Hl06n6|m0-<@Ef=%hWIRhUohMei@A&dD
zk7Y2+QUM;bangp(tryYjR$a1~nn5oSg)TQCGd@I5t`#1f{I+snGz%o%e?bjf^d@@Q+8ZvjK=i`V}ZX|`8wm8m)!YpvWk;N#=Roxae9WZJvO|pgi@5K
z)!5vyrZtFvDjxaS=fu8HDSf-Bbe)Sq#LN=^KD-*%I+99n7F3l4`h(nd`;b>o8c^2Z6VbDPRh1H*S;(rdb&3f_bkCjNLFL=$Fc
z70tOT7vhZKikBzY7zLGyuo(;9IgQb>W*ArKO4NO@tZX%OZnDmV*A*<}!qIo0HR4!I
z)OC)}7a@CSaf#MGClt&(ys3+bfECsjSoa7*JL3~AFb;~$Wt{V`&uBhlln{@ECr#)!TMK;;l
zV}arSt41w~YX6p;7L89&X&uQql&}8qobF4}jJX?Di2{du7VD8ZAw{~e{}B+)N4ZlI
ze@pmjvY&j^{;h6(qpL)}rTVx1{}d(vc_5%MMPIbX!=^4UPrK)KcKb*k7qA$g{3Ixh
zpRKF+J`J(HSs3PQjf05|Nm(0avqkjtuFR#ojdD-L$e9tJz3DOKYxFAQIAX1m61xCX
zs%=4B7O{aY6(zTd0WgEDZg
z$HrG`61c>7#6y%vXU&bLpD#If!3e8{khA<&E6-Zx>#}{4_tz#JDK81^KZ9IpgS+i>
zQgmJXKlmwH|Aqy?H^GG@uwyHvO2;NQCbVMnrpss&fNZ$V~yH+wGC_mUizpOk@AtJw*_^Twht3N@bA8EDQk>CwQROZ3w
z+P2Z{OFJ*06P!O_U3mH&pfYqV4|&-o<;=PRTV(hJ{0m!q$@cQO-HLEbW33*z%g;zj
zOKZyB>EfN*72<3C5Y$eUubgH*RJcEqh`^kcq-D_Npt!xzYj*vSp_9D2YqHPJnX4#LG@6
zR7=u6+#>3}WJX#Ys`$#h^TH1qzTp)yCbQ{6EmKdGu^;HhJ%tkyVmp-f|1=(1yQ4Jb
z*f0BaNYY5f2HY5gps_@PKUX29-E(oHjIswAvdb?HJK?XjI5U#Cj693$$`8CpUA;xb
za@i%?=xR?^rB{mFV4m9HKWJU3L8g8E-YnNaEaLcc-{o6&KNFmWZ2p9c!??^g#Ni$$
zMxo8T#(EY5gK0
zJo9^?iF&ZiXayl4GQ%Y!V)70(_=PRM8G5}M3k^ySH5Wbp)}k;7N6FHe|+=WCCJ*=o>-fgj1VHXIjlE*6h?EL`iCPsGbv951aR
z8~nw|eKFkW%^+8O9+!D-v|jsG{{4Kdd>)*GBn<+KOxs~B(I(1K>v8H{#M}Ked*tb+
zZ!_fA9T;x}DVLrTgG7^0UCX~av_8M--ULyCSI@P{bC|RHEnm51EC~MwYQdG4=s9JN
zuNNCzzO&oggZO5d=j3TAb;*rc=iF4=Uk<(UKz7zqWhdb>^$}Eiudv0@j|yu$Ln>5)5B-*_wu1_
z3zIZ^QfP%I117lIM5QJ{-8gt?Y{L>$51G;gqr7Znm%lrW%HrQ_3;KjrEpN%0&<=DY
zX;Z>dnzA>Da#JDcf5GSu;X<0YW;EXHlj4FO&wg!3XR7iRBxf;S{X@X26xcD!|0WCF
z!++?Mw=eWQljB}^fz?6CCoBSaADcJ!R2Yewp1ojBs$5lvH)*;r;
zxar}r4`zb&B_inhjEZrGjYLGQg_M?1Y!bO*QR*W3a~!SoZGMJ2!pFv>9$DrkrS=GQ
z8NQ1N22Jf^aXDst*^%BT%F9&=6Da6TQeVkANLtt#BXA8EwGOW-9VRMkG!HB{uC`%!
z1pc)-MtXLSIv_lS15fUL_YFT@
zIo$Myd|$&p(;m}iCqo0T^1tOwQ_dPbnWlQRD?`|R^Kow2*gJ5O85lkF%Pr(i~hMK>F&f|AuTD%3|B?Of1-5{fksrs}|3;leoV
z^cMCsj=?KVcW^&!Fzn#|hry
zK(j%$qsb$-;JZf6B{t(yEz(Io=sGWA
zZFq9cOmVYN{?~6U!y4iO)EUL<3JAQ+3UAx%10FWR@4%Qz3Xs+IOD#8LX?81E7feOq
zyYrW|l(xlB9nfh()Cc*?d&xZ+?715sWQ%K+0>^hQ%a$z%u8^`rgd&@~CP97Rol+0Y
zCAG+=J5!$`u)FFRw1cIDd(;-67gLehbY`1Jkmw$lH(
zA!IhNeYv@w5q^&v{XuQGgE$ylXP;WJHxwM68))pD%u@K%5K6`D;
z{&t9FQ2XdwKm-N~YF7wpBI~2J!MWye+|B0Pge@Z?wpj}o*+L)6l)_=tN}mo(ph^fk
z7=o%xCcQc}mZMotZ~ZmkR5^ouj`XUBu1soz`y20(c$O
literal 0
HcmV?d00001
From dea1fe919171a6c6b2568ce3cc8c2c5fd367ad56 Mon Sep 17 00:00:00 2001
From: Kevin Aleman
Date: Thu, 5 Oct 2023 11:56:04 -0600
Subject: [PATCH 35/35] feat: Save visitor's activity on agent's interaction
(#30222)
---
.changeset/brown-comics-cheat.md | 8 ++
.changeset/khaki-feet-dance.md | 5 +
.changeset/warm-melons-type.md | 7 +
.../app/apps/server/bridges/livechat.ts | 2 +-
.../app/apps/server/converters/rooms.js | 2 +-
.../app/apps/server/converters/visitors.js | 2 +-
.../server/functions/buildRegistrationData.ts | 8 +-
.../app/livechat/imports/server/rest/sms.js | 2 +-
.../app/livechat/server/api/lib/visitors.ts | 2 +-
.../app/livechat/server/api/v1/contact.ts | 2 +-
.../app/livechat/server/api/v1/message.ts | 2 +-
.../meteor/app/livechat/server/api/v1/room.ts | 2 +-
.../app/livechat/server/api/v1/visitor.ts | 6 +-
.../server/hooks/markRoomResponded.ts | 16 ++-
.../app/livechat/server/lib/Livechat.js | 26 ++--
.../app/livechat/server/lib/LivechatTyped.ts | 2 +-
.../app/livechat/server/methods/transfer.ts | 2 +-
.../app/statistics/server/lib/statistics.ts | 32 +++++
.../admin/info/DeploymentCard.stories.tsx | 4 +
.../admin/info/InformationPage.stories.tsx | 4 +
.../views/admin/info/UsageCard.stories.tsx | 4 +
.../hooks/onMessageSentParsePlaceholder.ts | 2 +-
.../hooks/handleNextAgentPreferredEvents.ts | 2 +-
.../server/hooks/resumeOnHold.ts | 2 +-
.../server/lib/VisitorInactivityMonitor.ts | 2 +-
.../server/methods/resumeOnHold.ts | 2 +-
.../EmailInbox/EmailInbox_Incoming.ts | 6 +-
.../server/lib/rooms/roomTypes/livechat.ts | 2 +-
.../meteor/server/models/raw/LivechatRooms.ts | 136 ++++++++++++++++++
.../server/models/raw/LivechatVisitors.ts | 86 ++++++++++-
.../end-to-end/api/livechat/09-visitors.ts | 24 +++-
.../src/OmnichannelTranscript.ts | 3 +-
packages/core-typings/src/ILivechatVisitor.ts | 2 +
packages/core-typings/src/IRoom.ts | 6 +-
packages/core-typings/src/IStats.ts | 5 +
.../core-typings/src/omnichannel/index.ts | 1 +
packages/core-typings/src/omnichannel/mac.ts | 5 +
.../src/models/ILivechatRoomsModel.ts | 12 +-
.../src/models/ILivechatVisitorsModel.ts | 12 ++
39 files changed, 404 insertions(+), 46 deletions(-)
create mode 100644 .changeset/brown-comics-cheat.md
create mode 100644 .changeset/khaki-feet-dance.md
create mode 100644 .changeset/warm-melons-type.md
create mode 100644 packages/core-typings/src/omnichannel/mac.ts
diff --git a/.changeset/brown-comics-cheat.md b/.changeset/brown-comics-cheat.md
new file mode 100644
index 000000000000..a7907979881b
--- /dev/null
+++ b/.changeset/brown-comics-cheat.md
@@ -0,0 +1,8 @@
+---
+"@rocket.chat/meteor": patch
+"@rocket.chat/core-typings": patch
+"@rocket.chat/model-typings": patch
+---
+
+chore: Calculate & Store MAC stats
+Added new info to the stats: `omnichannelContactsBySource`, `uniqueContactsOfLastMonth`, `uniqueContactsOfLastWeek`, `uniqueContactsOfYesterday`
diff --git a/.changeset/khaki-feet-dance.md b/.changeset/khaki-feet-dance.md
new file mode 100644
index 000000000000..a419afa34143
--- /dev/null
+++ b/.changeset/khaki-feet-dance.md
@@ -0,0 +1,5 @@
+---
+"@rocket.chat/meteor": patch
+---
+
+feat: Save visitor's activity on agent's interaction
diff --git a/.changeset/warm-melons-type.md b/.changeset/warm-melons-type.md
new file mode 100644
index 000000000000..5b187b8a7f11
--- /dev/null
+++ b/.changeset/warm-melons-type.md
@@ -0,0 +1,7 @@
+---
+"@rocket.chat/meteor": patch
+"@rocket.chat/core-typings": patch
+"@rocket.chat/omnichannel-services": patch
+---
+
+feat: Disable and annonimize visitors instead of removing
diff --git a/apps/meteor/app/apps/server/bridges/livechat.ts b/apps/meteor/app/apps/server/bridges/livechat.ts
index 71f7387e1aa5..76a0545c8801 100644
--- a/apps/meteor/app/apps/server/bridges/livechat.ts
+++ b/apps/meteor/app/apps/server/bridges/livechat.ts
@@ -223,7 +223,7 @@ export class AppLivechatBridge extends LivechatBridge {
}
return Promise.all(
- (await LivechatVisitors.find(query).toArray()).map(
+ (await LivechatVisitors.findEnabled(query).toArray()).map(
async (visitor) => visitor && this.orch.getConverters()?.get('visitors').convertVisitor(visitor),
),
);
diff --git a/apps/meteor/app/apps/server/converters/rooms.js b/apps/meteor/app/apps/server/converters/rooms.js
index ae38feff5eff..905534212836 100644
--- a/apps/meteor/app/apps/server/converters/rooms.js
+++ b/apps/meteor/app/apps/server/converters/rooms.js
@@ -37,7 +37,7 @@ export class AppRoomsConverter {
let v;
if (room.visitor) {
- const visitor = await LivechatVisitors.findOneById(room.visitor.id);
+ const visitor = await LivechatVisitors.findOneEnabledById(room.visitor.id);
const { lastMessageTs, phone } = room.visitorChannelInfo;
diff --git a/apps/meteor/app/apps/server/converters/visitors.js b/apps/meteor/app/apps/server/converters/visitors.js
index ba288c96d7b8..a9f5d450efad 100644
--- a/apps/meteor/app/apps/server/converters/visitors.js
+++ b/apps/meteor/app/apps/server/converters/visitors.js
@@ -9,7 +9,7 @@ export class AppVisitorsConverter {
}
async convertById(id) {
- const visitor = await LivechatVisitors.findOneById(id);
+ const visitor = await LivechatVisitors.findOneEnabledById(id);
return this.convertVisitor(visitor);
}
diff --git a/apps/meteor/app/cloud/server/functions/buildRegistrationData.ts b/apps/meteor/app/cloud/server/functions/buildRegistrationData.ts
index 2ad8ba29072a..f00718d2e779 100644
--- a/apps/meteor/app/cloud/server/functions/buildRegistrationData.ts
+++ b/apps/meteor/app/cloud/server/functions/buildRegistrationData.ts
@@ -32,7 +32,10 @@ export type WorkspaceRegistrationData = {
setupComplete: boolean;
connectionDisable: boolean;
npsEnabled: string;
+ // TODO: Evaluate naming
MAC: number;
+ // activeContactsBillingMonth: number;
+ // activeContactsYesterday: number;
};
export async function buildWorkspaceRegistrationData(contactEmail: T): Promise> {
@@ -80,7 +83,8 @@ export async function buildWorkspaceRegistrationData {
}
const id = await LivechatTyped.registerGuest(data);
- return LivechatVisitors.findOneById(id);
+ return LivechatVisitors.findOneEnabledById(id);
};
const normalizeLocationSharing = (payload) => {
diff --git a/apps/meteor/app/livechat/server/api/lib/visitors.ts b/apps/meteor/app/livechat/server/api/lib/visitors.ts
index e559aecc892e..0abed5197d78 100644
--- a/apps/meteor/app/livechat/server/api/lib/visitors.ts
+++ b/apps/meteor/app/livechat/server/api/lib/visitors.ts
@@ -6,7 +6,7 @@ import { callbacks } from '../../../../../lib/callbacks';
import { canAccessRoomAsync } from '../../../../authorization/server/functions/canAccessRoom';
export async function findVisitorInfo({ visitorId }: { visitorId: IVisitor['_id'] }) {
- const visitor = await LivechatVisitors.findOneById(visitorId);
+ const visitor = await LivechatVisitors.findOneEnabledById(visitorId);
if (!visitor) {
throw new Error('visitor-not-found');
}
diff --git a/apps/meteor/app/livechat/server/api/v1/contact.ts b/apps/meteor/app/livechat/server/api/v1/contact.ts
index 517acf33f137..57c1d117f1b0 100644
--- a/apps/meteor/app/livechat/server/api/v1/contact.ts
+++ b/apps/meteor/app/livechat/server/api/v1/contact.ts
@@ -33,7 +33,7 @@ API.v1.addRoute(
contactId: String,
});
- const contact = await LivechatVisitors.findOneById(this.queryParams.contactId);
+ const contact = await LivechatVisitors.findOneEnabledById(this.queryParams.contactId);
return API.v1.success({ contact });
},
diff --git a/apps/meteor/app/livechat/server/api/v1/message.ts b/apps/meteor/app/livechat/server/api/v1/message.ts
index 2b6f4c00af53..104e2ece94d5 100644
--- a/apps/meteor/app/livechat/server/api/v1/message.ts
+++ b/apps/meteor/app/livechat/server/api/v1/message.ts
@@ -269,7 +269,7 @@ API.v1.addRoute(
guest.connectionData = normalizeHttpHeaderData(this.request.headers);
const visitorId = await LivechatTyped.registerGuest(guest);
- visitor = await LivechatVisitors.findOneById(visitorId);
+ visitor = await LivechatVisitors.findOneEnabledById(visitorId);
}
const sentMessages = await Promise.all(
diff --git a/apps/meteor/app/livechat/server/api/v1/room.ts b/apps/meteor/app/livechat/server/api/v1/room.ts
index 0fe60248bfba..86629e636bf8 100644
--- a/apps/meteor/app/livechat/server/api/v1/room.ts
+++ b/apps/meteor/app/livechat/server/api/v1/room.ts
@@ -326,7 +326,7 @@ API.v1.addRoute(
throw new Error('This_conversation_is_already_closed');
}
- const guest = await LivechatVisitors.findOneById(room.v?._id);
+ const guest = await LivechatVisitors.findOneEnabledById(room.v?._id);
const transferedBy = this.user satisfies TransferByData;
transferData.transferredBy = normalizeTransferredByData(transferedBy, room);
if (transferData.userId) {
diff --git a/apps/meteor/app/livechat/server/api/v1/visitor.ts b/apps/meteor/app/livechat/server/api/v1/visitor.ts
index 012b412639ea..ae9d1ea4fd83 100644
--- a/apps/meteor/app/livechat/server/api/v1/visitor.ts
+++ b/apps/meteor/app/livechat/server/api/v1/visitor.ts
@@ -45,7 +45,7 @@ API.v1.addRoute('livechat/visitor', {
const visitorId = await LivechatTyped.registerGuest(guest);
- let visitor = await VisitorsRaw.findOneById(visitorId, {});
+ let visitor = await VisitorsRaw.findOneEnabledById(visitorId, {});
if (visitor) {
const extraQuery = await callbacks.run('livechat.applyRoomRestrictions', {});
// If it's updating an existing visitor, it must also update the roomInfo
@@ -65,7 +65,7 @@ API.v1.addRoute('livechat/visitor', {
}
}
- visitor = await VisitorsRaw.findOneById(visitorId, {});
+ visitor = await VisitorsRaw.findOneEnabledById(visitorId, {});
}
if (!visitor) {
@@ -122,7 +122,7 @@ API.v1.addRoute('livechat/visitor/:token', {
const { _id } = visitor;
const result = await Livechat.removeGuest(_id);
- if (!result) {
+ if (!result.modifiedCount) {
throw new Meteor.Error('error-removing-visitor', 'An error ocurred while deleting visitor');
}
diff --git a/apps/meteor/app/livechat/server/hooks/markRoomResponded.ts b/apps/meteor/app/livechat/server/hooks/markRoomResponded.ts
index 5ebf924e7334..ad68fcf5ce5c 100644
--- a/apps/meteor/app/livechat/server/hooks/markRoomResponded.ts
+++ b/apps/meteor/app/livechat/server/hooks/markRoomResponded.ts
@@ -1,6 +1,7 @@
import type { IOmnichannelRoom } from '@rocket.chat/core-typings';
import { isOmnichannelRoom, isEditedMessage } from '@rocket.chat/core-typings';
-import { LivechatRooms } from '@rocket.chat/models';
+import { LivechatRooms, LivechatVisitors } from '@rocket.chat/models';
+import moment from 'moment';
import { callbacks } from '../../../../lib/callbacks';
@@ -26,6 +27,19 @@ callbacks.add(
return message;
}
+ // Return YYYY-MM from moment
+ const monthYear = moment().format('YYYY-MM');
+ const isVisitorActive = await LivechatVisitors.isVisitorActiveOnPeriod(room.v._id, monthYear);
+ if (!isVisitorActive) {
+ await LivechatVisitors.markVisitorActiveForPeriod(room.v._id, monthYear);
+ }
+
+ await LivechatRooms.markVisitorActiveForPeriod(room._id, monthYear);
+
+ if (room.responseBy) {
+ await LivechatRooms.setAgentLastMessageTs(room._id);
+ }
+
// check if room is yet awaiting for response from visitor
if (!room.waitingResponse) {
// case where agent sends second message or any subsequent message in a room before visitor responds to the first message
diff --git a/apps/meteor/app/livechat/server/lib/Livechat.js b/apps/meteor/app/livechat/server/lib/Livechat.js
index 52138740e295..ffd3a29b229f 100644
--- a/apps/meteor/app/livechat/server/lib/Livechat.js
+++ b/apps/meteor/app/livechat/server/lib/Livechat.js
@@ -298,7 +298,7 @@ export const Livechat = {
async forwardOpenChats(userId) {
Livechat.logger.debug(`Transferring open chats for user ${userId}`);
for await (const room of LivechatRooms.findOpenByAgent(userId)) {
- const guest = await LivechatVisitors.findOneById(room.v._id);
+ const guest = await LivechatVisitors.findOneEnabledById(room.v._id);
const user = await Users.findOneById(userId);
const { _id, username, name } = user;
const transferredBy = normalizeTransferredByData({ _id, username, name }, room);
@@ -462,7 +462,7 @@ export const Livechat = {
},
async getLivechatRoomGuestInfo(room) {
- const visitor = await LivechatVisitors.findOneById(room.v._id);
+ const visitor = await LivechatVisitors.findOneEnabledById(room.v._id);
const agent = await Users.findOneById(room.servedBy && room.servedBy._id);
const ua = new UAParser();
@@ -604,16 +604,15 @@ export const Livechat = {
},
async removeGuest(_id) {
- check(_id, String);
- const guest = await LivechatVisitors.findOneById(_id, { projection: { _id: 1 } });
+ const guest = await LivechatVisitors.findOneEnabledById(_id, { projection: { _id: 1, token: 1 } });
if (!guest) {
throw new Meteor.Error('error-invalid-guest', 'Invalid guest', {
method: 'livechat:removeGuest',
});
}
- await this.cleanGuestHistory(_id);
- return LivechatVisitors.removeById(_id);
+ await this.cleanGuestHistory(guest);
+ return LivechatVisitors.disableById(_id);
},
async setUserStatusLivechat(userId, status) {
@@ -628,16 +627,13 @@ export const Livechat = {
return user;
},
- async cleanGuestHistory(_id) {
- const guest = await LivechatVisitors.findOneById(_id);
- if (!guest) {
- throw new Meteor.Error('error-invalid-guest', 'Invalid guest', {
- method: 'livechat:cleanGuestHistory',
- });
- }
-
+ async cleanGuestHistory(guest) {
const { token } = guest;
- check(token, String);
+
+ // This shouldn't be possible, but just in case
+ if (!token) {
+ throw new Error('error-invalid-guest');
+ }
const extraQuery = await callbacks.run('livechat.applyRoomRestrictions', {});
const cursor = LivechatRooms.findByVisitorToken(token, extraQuery);
diff --git a/apps/meteor/app/livechat/server/lib/LivechatTyped.ts b/apps/meteor/app/livechat/server/lib/LivechatTyped.ts
index 1c60a257d319..c443bc7873c7 100644
--- a/apps/meteor/app/livechat/server/lib/LivechatTyped.ts
+++ b/apps/meteor/app/livechat/server/lib/LivechatTyped.ts
@@ -305,7 +305,7 @@ class LivechatClass {
!(await LivechatDepartment.findOneById>(guest.department, { projection: { _id: 1 } }))
) {
await LivechatVisitors.removeDepartmentById(guest._id);
- const tmpGuest = await LivechatVisitors.findOneById(guest._id);
+ const tmpGuest = await LivechatVisitors.findOneEnabledById(guest._id);
if (tmpGuest) {
guest = tmpGuest;
}
diff --git a/apps/meteor/app/livechat/server/methods/transfer.ts b/apps/meteor/app/livechat/server/methods/transfer.ts
index 2dc796fc6c94..3817b10bf42b 100644
--- a/apps/meteor/app/livechat/server/methods/transfer.ts
+++ b/apps/meteor/app/livechat/server/methods/transfer.ts
@@ -58,7 +58,7 @@ Meteor.methods({
});
}
- const guest = await LivechatVisitors.findOneById(room.v?._id);
+ const guest = await LivechatVisitors.findOneEnabledById(room.v?._id);
const user = await Meteor.userAsync();
diff --git a/apps/meteor/app/statistics/server/lib/statistics.ts b/apps/meteor/app/statistics/server/lib/statistics.ts
index 89b068c11341..c6180c189124 100644
--- a/apps/meteor/app/statistics/server/lib/statistics.ts
+++ b/apps/meteor/app/statistics/server/lib/statistics.ts
@@ -24,8 +24,10 @@ import {
LivechatCustomField,
Subscriptions,
Users,
+ LivechatRooms,
} from '@rocket.chat/models';
import { MongoInternals } from 'meteor/mongo';
+import moment from 'moment';
import { getStatistics as getEnterpriseStatistics } from '../../../../ee/app/license/server/getStatistics';
import { readSecondaryPreferred } from '../../../../server/database/readSecondaryPreferred';
@@ -269,6 +271,36 @@ export const statistics = {
}),
);
+ const defaultValue = { contactsCount: 0, conversationsCount: 0, sources: [] };
+ const billablePeriod = moment.utc().format('YYYY-MM');
+ statsPms.push(
+ LivechatRooms.getMACStatisticsForPeriod(billablePeriod).then(([result]) => {
+ statistics.omnichannelContactsBySource = result || defaultValue;
+ }),
+ );
+
+ const monthAgo = moment.utc().subtract(30, 'days').toDate();
+ const today = moment.utc().toDate();
+ statsPms.push(
+ LivechatRooms.getMACStatisticsBetweenDates(monthAgo, today).then(([result]) => {
+ statistics.uniqueContactsOfLastMonth = result || defaultValue;
+ }),
+ );
+
+ const weekAgo = moment.utc().subtract(7, 'days').toDate();
+ statsPms.push(
+ LivechatRooms.getMACStatisticsBetweenDates(weekAgo, today).then(([result]) => {
+ statistics.uniqueContactsOfLastWeek = result || defaultValue;
+ }),
+ );
+
+ const yesterday = moment.utc().subtract(1, 'days').toDate();
+ statsPms.push(
+ LivechatRooms.getMACStatisticsBetweenDates(yesterday, today).then(([result]) => {
+ statistics.uniqueContactsOfYesterday = result || defaultValue;
+ }),
+ );
+
// Message statistics
statistics.totalChannelMessages = (await Rooms.findByType('c', { projection: { msgs: 1 } }).toArray()).reduce(
function _countChannelMessages(num: number, room: IRoom) {
diff --git a/apps/meteor/client/views/admin/info/DeploymentCard.stories.tsx b/apps/meteor/client/views/admin/info/DeploymentCard.stories.tsx
index 98aa3a7073ff..7570cb71bd1c 100644
--- a/apps/meteor/client/views/admin/info/DeploymentCard.stories.tsx
+++ b/apps/meteor/client/views/admin/info/DeploymentCard.stories.tsx
@@ -170,6 +170,10 @@ export default {
uniqueOSOfYesterday: { data: [], day: 0, month: 0, year: 0 },
uniqueOSOfLastWeek: { data: [], day: 0, month: 0, year: 0 },
uniqueOSOfLastMonth: { data: [], day: 0, month: 0, year: 0 },
+ omnichannelContactsBySource: { contactsCount: 0, conversationsCount: 0, sources: [] },
+ uniqueContactsOfLastMonth: { contactsCount: 0, conversationsCount: 0, sources: [] },
+ uniqueContactsOfLastWeek: { contactsCount: 0, conversationsCount: 0, sources: [] },
+ uniqueContactsOfYesterday: { contactsCount: 0, conversationsCount: 0, sources: [] },
apps: {
engineVersion: 'x.y.z',
enabled: false,
diff --git a/apps/meteor/client/views/admin/info/InformationPage.stories.tsx b/apps/meteor/client/views/admin/info/InformationPage.stories.tsx
index a6ef0c8e9289..0a8e97710ca5 100644
--- a/apps/meteor/client/views/admin/info/InformationPage.stories.tsx
+++ b/apps/meteor/client/views/admin/info/InformationPage.stories.tsx
@@ -200,6 +200,10 @@ export default {
uniqueOSOfYesterday: { data: [], day: 0, month: 0, year: 0 },
uniqueOSOfLastWeek: { data: [], day: 0, month: 0, year: 0 },
uniqueOSOfLastMonth: { data: [], day: 0, month: 0, year: 0 },
+ omnichannelContactsBySource: { contactsCount: 0, conversationsCount: 0, sources: [] },
+ uniqueContactsOfLastMonth: { contactsCount: 0, conversationsCount: 0, sources: [] },
+ uniqueContactsOfLastWeek: { contactsCount: 0, conversationsCount: 0, sources: [] },
+ uniqueContactsOfYesterday: { contactsCount: 0, conversationsCount: 0, sources: [] },
apps: {
engineVersion: 'x.y.z',
enabled: false,
diff --git a/apps/meteor/client/views/admin/info/UsageCard.stories.tsx b/apps/meteor/client/views/admin/info/UsageCard.stories.tsx
index da49ee88fa6b..bfe56b6db2d8 100644
--- a/apps/meteor/client/views/admin/info/UsageCard.stories.tsx
+++ b/apps/meteor/client/views/admin/info/UsageCard.stories.tsx
@@ -148,6 +148,10 @@ export default {
uniqueOSOfYesterday: { data: [], day: 0, month: 0, year: 0 },
uniqueOSOfLastWeek: { data: [], day: 0, month: 0, year: 0 },
uniqueOSOfLastMonth: { data: [], day: 0, month: 0, year: 0 },
+ omnichannelContactsBySource: { contactsCount: 0, conversationsCount: 0, sources: [] },
+ uniqueContactsOfLastMonth: { contactsCount: 0, conversationsCount: 0, sources: [] },
+ uniqueContactsOfLastWeek: { contactsCount: 0, conversationsCount: 0, sources: [] },
+ uniqueContactsOfYesterday: { contactsCount: 0, conversationsCount: 0, sources: [] },
apps: {
engineVersion: 'x.y.z',
enabled: false,
diff --git a/apps/meteor/ee/app/canned-responses/server/hooks/onMessageSentParsePlaceholder.ts b/apps/meteor/ee/app/canned-responses/server/hooks/onMessageSentParsePlaceholder.ts
index 4d13df42c104..1cb016a33be6 100644
--- a/apps/meteor/ee/app/canned-responses/server/hooks/onMessageSentParsePlaceholder.ts
+++ b/apps/meteor/ee/app/canned-responses/server/hooks/onMessageSentParsePlaceholder.ts
@@ -48,7 +48,7 @@ const handleBeforeSaveMessage = async (message: IMessage, room?: IOmnichannelRoo
}
const visitorId = room?.v?._id;
const agent = (await Users.findOneById(agentId, { projection: { name: 1, _id: 1, emails: 1 } })) || {};
- const visitor = visitorId && ((await LivechatVisitors.findOneById(visitorId, {})) || {});
+ const visitor = visitorId && ((await LivechatVisitors.findOneEnabledById(visitorId, {})) || {});
Object.keys(placeholderFields).map((field) => {
const templateKey = `{{${field}}}`;
diff --git a/apps/meteor/ee/app/livechat-enterprise/server/hooks/handleNextAgentPreferredEvents.ts b/apps/meteor/ee/app/livechat-enterprise/server/hooks/handleNextAgentPreferredEvents.ts
index b7026e3b2da4..21fae96e3555 100644
--- a/apps/meteor/ee/app/livechat-enterprise/server/hooks/handleNextAgentPreferredEvents.ts
+++ b/apps/meteor/ee/app/livechat-enterprise/server/hooks/handleNextAgentPreferredEvents.ts
@@ -90,7 +90,7 @@ callbacks.add(
}
const { _id: guestId } = defaultGuest;
- const guest = await LivechatVisitors.findOneById(guestId, {
+ const guest = await LivechatVisitors.findOneEnabledById(guestId, {
projection: { lastAgent: 1, token: 1, contactManager: 1 },
});
if (!guest) {
diff --git a/apps/meteor/ee/app/livechat-enterprise/server/hooks/resumeOnHold.ts b/apps/meteor/ee/app/livechat-enterprise/server/hooks/resumeOnHold.ts
index 8c9ce3e65aaf..8a04166e1b72 100644
--- a/apps/meteor/ee/app/livechat-enterprise/server/hooks/resumeOnHold.ts
+++ b/apps/meteor/ee/app/livechat-enterprise/server/hooks/resumeOnHold.ts
@@ -12,7 +12,7 @@ const resumeOnHoldCommentAndUser = async (room: IOmnichannelRoom): Promise<{ com
v: { _id: visitorId },
_id: rid,
} = room;
- const visitor = await LivechatVisitors.findOneById>(visitorId, {
+ const visitor = await LivechatVisitors.findOneEnabledById>(visitorId, {
projection: { name: 1, username: 1 },
});
if (!visitor) {
diff --git a/apps/meteor/ee/app/livechat-enterprise/server/lib/VisitorInactivityMonitor.ts b/apps/meteor/ee/app/livechat-enterprise/server/lib/VisitorInactivityMonitor.ts
index 824296d1e673..12233a9127a8 100644
--- a/apps/meteor/ee/app/livechat-enterprise/server/lib/VisitorInactivityMonitor.ts
+++ b/apps/meteor/ee/app/livechat-enterprise/server/lib/VisitorInactivityMonitor.ts
@@ -148,7 +148,7 @@ export class VisitorInactivityMonitor {
}
private async getDefaultAbandonedCustomMessage(abandonmentAction: 'close' | 'on-hold', visitorId: string) {
- const visitor = await LivechatVisitors.findOneById>(visitorId, {
+ const visitor = await LivechatVisitors.findOneEnabledById>(visitorId, {
projection: {
name: 1,
username: 1,
diff --git a/apps/meteor/ee/app/livechat-enterprise/server/methods/resumeOnHold.ts b/apps/meteor/ee/app/livechat-enterprise/server/methods/resumeOnHold.ts
index 2507dd683145..99a80b3b0b88 100644
--- a/apps/meteor/ee/app/livechat-enterprise/server/methods/resumeOnHold.ts
+++ b/apps/meteor/ee/app/livechat-enterprise/server/methods/resumeOnHold.ts
@@ -19,7 +19,7 @@ async function resolveOnHoldCommentInfo(options: { clientAction: boolean }, room
const {
v: { _id: visitorId },
} = room;
- const visitor = await LivechatVisitors.findOneById>(visitorId, {
+ const visitor = await LivechatVisitors.findOneEnabledById>(visitorId, {
projection: { name: 1, username: 1 },
});
if (!visitor) {
diff --git a/apps/meteor/server/features/EmailInbox/EmailInbox_Incoming.ts b/apps/meteor/server/features/EmailInbox/EmailInbox_Incoming.ts
index d71190cb0b6d..939d91661650 100644
--- a/apps/meteor/server/features/EmailInbox/EmailInbox_Incoming.ts
+++ b/apps/meteor/server/features/EmailInbox/EmailInbox_Incoming.ts
@@ -35,7 +35,7 @@ async function getGuestByEmail(email: string, name: string, department = ''): Pr
return guest;
}
await LivechatTyped.setDepartmentForGuest({ token: guest.token, department });
- return LivechatVisitors.findOneById(guest._id, {});
+ return LivechatVisitors.findOneEnabledById(guest._id, {});
}
return guest;
}
@@ -47,7 +47,9 @@ async function getGuestByEmail(email: string, name: string, department = ''): Pr
department,
});
- const newGuest = await LivechatVisitors.findOneById(userId);
+ const newGuest = await LivechatVisitors.findOneEnabledById(userId);
+ logger.debug(`Guest ${userId} for visitor ${email} created`);
+
if (newGuest) {
return newGuest;
}
diff --git a/apps/meteor/server/lib/rooms/roomTypes/livechat.ts b/apps/meteor/server/lib/rooms/roomTypes/livechat.ts
index 88393088541e..92d722ac2bb0 100644
--- a/apps/meteor/server/lib/rooms/roomTypes/livechat.ts
+++ b/apps/meteor/server/lib/rooms/roomTypes/livechat.ts
@@ -39,7 +39,7 @@ roomCoordinator.add(LivechatRoomType, {
},
async getMsgSender(senderId) {
- return LivechatVisitors.findOneById(senderId);
+ return LivechatVisitors.findOneEnabledById(senderId);
},
getReadReceiptsExtraData(message) {
diff --git a/apps/meteor/server/models/raw/LivechatRooms.ts b/apps/meteor/server/models/raw/LivechatRooms.ts
index 38eab9056586..bf44a51b7f64 100644
--- a/apps/meteor/server/models/raw/LivechatRooms.ts
+++ b/apps/meteor/server/models/raw/LivechatRooms.ts
@@ -8,6 +8,7 @@ import type {
ILivechatPriority,
IOmnichannelServiceLevelAgreements,
ReportResult,
+ MACStats,
} from '@rocket.chat/core-typings';
import { UserStatus } from '@rocket.chat/core-typings';
import type { ILivechatRoomsModel } from '@rocket.chat/model-typings';
@@ -74,6 +75,7 @@ export class LivechatRoomsRaw extends BaseRaw implements ILive
{ key: { departmentId: 1, ts: 1 }, partialFilterExpression: { departmentId: { $exists: true }, t: 'l' } },
{ key: { 'tags.0': 1, 'ts': 1 }, partialFilterExpression: { 'tags.0': { $exists: true }, 't': 'l' } },
{ key: { servedBy: 1, ts: 1 }, partialFilterExpression: { servedBy: { $exists: true }, t: 'l' } },
+ { key: { 'v.activity': 1, 'ts': 1 }, partialFilterExpression: { 'v.activity': { $exists: true }, 't': 'l' } },
];
}
@@ -2448,6 +2450,140 @@ export class LivechatRoomsRaw extends BaseRaw implements ILive
return this.updateOne(query, update);
}
+ markVisitorActiveForPeriod(rid: string, period: string): Promise {
+ const query = {
+ _id: rid,
+ };
+
+ const update = {
+ $addToSet: {
+ 'v.activity': period,
+ },
+ };
+
+ return this.updateOne(query, update);
+ }
+
+ async getMACStatisticsForPeriod(period: string): Promise {
+ return this.col
+ .aggregate([
+ {
+ $match: {
+ 't': 'l',
+ 'v.activity': period,
+ },
+ },
+ {
+ $group: {
+ _id: {
+ source: {
+ $ifNull: ['$source.alias', '$source.type'],
+ },
+ },
+ contactsCount: {
+ $addToSet: '$v._id',
+ },
+ conversationsCount: {
+ $sum: 1,
+ },
+ },
+ },
+ {
+ $group: {
+ _id: null,
+ sources: {
+ $push: {
+ source: '$_id.source',
+ contactsCount: {
+ $size: '$contactsCount',
+ },
+ conversationsCount: '$conversationsCount',
+ },
+ },
+ totalContactsCount: {
+ $sum: {
+ $size: '$contactsCount',
+ },
+ },
+ totalConversationsCount: {
+ $sum: '$conversationsCount',
+ },
+ },
+ },
+ {
+ $project: {
+ _id: 0,
+ contactsCount: '$totalContactsCount',
+ conversationsCount: '$totalConversationsCount',
+ sources: 1,
+ },
+ },
+ ])
+ .toArray();
+ }
+
+ async getMACStatisticsBetweenDates(start: Date, end: Date): Promise {
+ return this.col
+ .aggregate([
+ {
+ $match: {
+ 't': 'l',
+ 'v.activity': { $exists: true },
+ 'ts': {
+ $gte: start,
+ $lt: end,
+ },
+ },
+ },
+ {
+ $group: {
+ _id: {
+ source: {
+ $ifNull: ['$source.alias', '$source.type'],
+ },
+ },
+ contactsCount: {
+ $addToSet: '$v._id',
+ },
+ conversationsCount: {
+ $sum: 1,
+ },
+ },
+ },
+ {
+ $group: {
+ _id: null,
+ sources: {
+ $push: {
+ source: '$_id.source',
+ contactsCount: {
+ $size: '$contactsCount',
+ },
+ conversationsCount: '$conversationsCount',
+ },
+ },
+ totalContactsCount: {
+ $sum: {
+ $size: '$contactsCount',
+ },
+ },
+ totalConversationsCount: {
+ $sum: '$conversationsCount',
+ },
+ },
+ },
+ {
+ $project: {
+ _id: 0,
+ contactsCount: '$totalContactsCount',
+ conversationsCount: '$totalConversationsCount',
+ sources: 1,
+ },
+ },
+ ])
+ .toArray();
+ }
+
async unsetAllPredictedVisitorAbandonment(): Promise {
throw new Error('Method not implemented.');
}
diff --git a/apps/meteor/server/models/raw/LivechatVisitors.ts b/apps/meteor/server/models/raw/LivechatVisitors.ts
index 2df2ae09882b..7b478bab43d6 100644
--- a/apps/meteor/server/models/raw/LivechatVisitors.ts
+++ b/apps/meteor/server/models/raw/LivechatVisitors.ts
@@ -32,6 +32,8 @@ export class LivechatVisitorsRaw extends BaseRaw implements IL
{ key: { username: 1 } },
{ key: { 'contactMananger.username': 1 }, sparse: true },
{ key: { 'livechatData.$**': 1 } },
+ { key: { activity: 1 }, partialFilterExpression: { activity: { $exists: true } } },
+ { key: { disabled: 1 }, partialFilterExpression: { disabled: { $exists: true } } },
];
}
@@ -63,9 +65,29 @@ export class LivechatVisitorsRaw extends BaseRaw implements IL
return this.find(query, options);
}
+ findEnabled(query: Filter, options?: FindOptions): FindCursor {
+ return this.find(
+ {
+ ...query,
+ disabled: { $ne: true },
+ },
+ options,
+ );
+ }
+
+ findOneEnabledById(_id: string, options?: FindOptions): Promise {
+ const query = {
+ _id,
+ disabled: { $ne: true },
+ };
+
+ return this.findOne(query, options);
+ }
+
findVisitorByToken(token: string): FindCursor {
const query = {
token,
+ disabled: { $ne: true },
};
return this.find(query);
@@ -81,6 +103,7 @@ export class LivechatVisitorsRaw extends BaseRaw implements IL
getVisitorsBetweenDate({ start, end, department }: { start: Date; end: Date; department?: string }): FindCursor {
const query = {
+ disabled: { $ne: true },
_updatedAt: {
$gte: new Date(start),
$lt: new Date(end),
@@ -166,7 +189,7 @@ export class LivechatVisitorsRaw extends BaseRaw implements IL
options?: FindOptions,
): Promise>> {
if (!emailOrPhone && !nameOrUsername && allowedCustomFields.length === 0) {
- return this.findPaginated({}, options);
+ return this.findPaginated({ disabled: { $ne: true } }, options);
}
const query: Filter = {
@@ -193,6 +216,7 @@ export class LivechatVisitorsRaw extends BaseRaw implements IL
: []),
...allowedCustomFields.map((c: string) => ({ [`livechatData.${c}`]: nameOrUsername })),
],
+ disabled: { $ne: true },
};
return this.findPaginated(query, options);
@@ -204,7 +228,9 @@ export class LivechatVisitorsRaw extends BaseRaw implements IL
customFields?: { [key: string]: RegExp },
): Promise {
const query = Object.assign(
- {},
+ {
+ disabled: { $ne: true },
+ },
{
...(email && { visitorEmails: { address: email } }),
...(phone && { phone: { phoneNumber: phone } }),
@@ -212,7 +238,7 @@ export class LivechatVisitorsRaw extends BaseRaw implements IL
},
);
- if (Object.keys(query).length === 0) {
+ if (Object.keys(query).length === 1) {
return null;
}
@@ -365,6 +391,60 @@ export class LivechatVisitorsRaw extends BaseRaw implements IL
},
);
}
+
+ isVisitorActiveOnPeriod(visitorId: string, period: string): Promise {
+ const query = {
+ _id: visitorId,
+ activity: period,
+ };
+
+ return this.findOne(query, { projection: { _id: 1 } }).then(Boolean);
+ }
+
+ markVisitorActiveForPeriod(visitorId: string, period: string): Promise {
+ const query = {
+ _id: visitorId,
+ };
+
+ const update = {
+ $push: {
+ activity: {
+ $each: [period],
+ $slice: -12,
+ },
+ },
+ };
+
+ return this.updateOne(query, update);
+ }
+
+ disableById(_id: string): Promise {
+ return this.updateOne(
+ { _id },
+ {
+ $set: { disabled: true },
+ $unset: {
+ department: 1,
+ contactManager: 1,
+ token: 1,
+ visitorEmails: 1,
+ phone: 1,
+ name: 1,
+ livechatData: 1,
+ lastChat: 1,
+ ip: 1,
+ host: 1,
+ userAgent: 1,
+ },
+ },
+ );
+ }
+
+ countVisitorsOnPeriod(period: string): Promise {
+ return this.countDocuments({
+ activity: period,
+ });
+ }
}
type DeepWriteable = { -readonly [P in keyof T]: DeepWriteable };
diff --git a/apps/meteor/tests/end-to-end/api/livechat/09-visitors.ts b/apps/meteor/tests/end-to-end/api/livechat/09-visitors.ts
index a3ca544de20c..55ef4402da39 100644
--- a/apps/meteor/tests/end-to-end/api/livechat/09-visitors.ts
+++ b/apps/meteor/tests/end-to-end/api/livechat/09-visitors.ts
@@ -2,7 +2,8 @@ import { faker } from '@faker-js/faker';
import type { ILivechatVisitor } from '@rocket.chat/core-typings';
import { expect } from 'chai';
import { before, describe, it } from 'mocha';
-import type { Response } from 'supertest';
+import moment from 'moment';
+import { type Response } from 'supertest';
import { getCredentials, api, request, credentials } from '../../../data/api-data';
import { createCustomField, deleteCustomField } from '../../../data/livechat/custom-fields';
@@ -334,6 +335,27 @@ describe('LIVECHAT - visitors', function () {
});
});
+ it('should return visitor activity field when visitor was active on month', async () => {
+ // Activity is determined by a conversation in which an agent has engaged (sent a message)
+ // For a visitor to be considered active, they must have had a conversation in the last 30 days
+ const period = moment().format('YYYY-MM');
+ const { visitor, room } = await startANewLivechatRoomAndTakeIt();
+ // agent should send a message on the room
+ await request
+ .post(api('chat.sendMessage'))
+ .set(credentials)
+ .send({
+ message: {
+ rid: room._id,
+ msg: 'test',
+ },
+ });
+
+ const activeVisitor = await getLivechatVisitorByToken(visitor.token);
+ expect(activeVisitor).to.have.property('activity');
+ expect(activeVisitor.activity).to.include(period);
+ });
+
it("should return a 'error-removing-visitor' error when removeGuest's result is false", async () => {
await request
.delete(api('livechat/visitor/123'))
diff --git a/ee/packages/omnichannel-services/src/OmnichannelTranscript.ts b/ee/packages/omnichannel-services/src/OmnichannelTranscript.ts
index ce21e963911b..0e135d5ed263 100644
--- a/ee/packages/omnichannel-services/src/OmnichannelTranscript.ts
+++ b/ee/packages/omnichannel-services/src/OmnichannelTranscript.ts
@@ -304,7 +304,8 @@ export class OmnichannelTranscript extends ServiceClass implements IOmnichannelT
const messages = await this.getMessagesFromRoom({ rid: room._id });
const visitor =
- room.v && (await LivechatVisitors.findOneById(room.v._id, { projection: { _id: 1, name: 1, username: 1, visitorEmails: 1 } }));
+ room.v &&
+ (await LivechatVisitors.findOneEnabledById(room.v._id, { projection: { _id: 1, name: 1, username: 1, visitorEmails: 1 } }));
const agent =
room.servedBy && (await Users.findOneAgentById(room.servedBy._id, { projection: { _id: 1, name: 1, username: 1, utcOffset: 1 } }));
diff --git a/packages/core-typings/src/ILivechatVisitor.ts b/packages/core-typings/src/ILivechatVisitor.ts
index d22ea36aa7c6..e80d63ab15d0 100644
--- a/packages/core-typings/src/ILivechatVisitor.ts
+++ b/packages/core-typings/src/ILivechatVisitor.ts
@@ -47,6 +47,8 @@ export interface ILivechatVisitor extends IRocketChatRecord {
contactManager?: {
username: string;
};
+ activity?: string[];
+ disabled?: boolean;
}
export interface ILivechatVisitorDTO {
diff --git a/packages/core-typings/src/IRoom.ts b/packages/core-typings/src/IRoom.ts
index 875dea70781e..523450e9594d 100644
--- a/packages/core-typings/src/IRoom.ts
+++ b/packages/core-typings/src/IRoom.ts
@@ -151,7 +151,11 @@ export enum OmnichannelSourceType {
export interface IOmnichannelGenericRoom extends Omit {
t: 'l' | 'v';
- v: Pick & { lastMessageTs?: Date; phone?: string };
+ v: Pick & {
+ lastMessageTs?: Date;
+ phone?: string;
+ activity?: string[];
+ };
email?: {
// Data used when the room is created from an email, via email Integration.
inbox: string;
diff --git a/packages/core-typings/src/IStats.ts b/packages/core-typings/src/IStats.ts
index 6bbc2da81b74..70f9f638358f 100644
--- a/packages/core-typings/src/IStats.ts
+++ b/packages/core-typings/src/IStats.ts
@@ -3,6 +3,7 @@ import type { CpuInfo } from 'os';
import type { DeviceSessionAggregationResult, OSSessionAggregationResult, UserSessionAggregationResult } from './ISession';
import type { ISettingStatisticsObject } from './ISetting';
import type { ITeamStats } from './ITeam';
+import type { MACStats } from './omnichannel';
export interface IStats {
_id: string;
@@ -93,6 +94,10 @@ export interface IStats {
mongoStorageEngine: string;
pushQueue: number;
omnichannelSources: { [key: string]: number | string }[];
+ omnichannelContactsBySource: MACStats;
+ uniqueContactsOfLastMonth: MACStats;
+ uniqueContactsOfLastWeek: MACStats;
+ uniqueContactsOfYesterday: MACStats;
departments: number;
archivedDepartments: number;
routingAlgorithm: string;
diff --git a/packages/core-typings/src/omnichannel/index.ts b/packages/core-typings/src/omnichannel/index.ts
index 703cf3b4ca77..c6235175dafc 100644
--- a/packages/core-typings/src/omnichannel/index.ts
+++ b/packages/core-typings/src/omnichannel/index.ts
@@ -2,3 +2,4 @@ export * from './sms';
export * from './routing';
export * from './queue';
export * from './reports';
+export * from './mac';
diff --git a/packages/core-typings/src/omnichannel/mac.ts b/packages/core-typings/src/omnichannel/mac.ts
new file mode 100644
index 000000000000..8591edbb0287
--- /dev/null
+++ b/packages/core-typings/src/omnichannel/mac.ts
@@ -0,0 +1,5 @@
+export type MACStats = {
+ contactsCount: number;
+ conversationsCount: number;
+ sources: { source: string; contactsCount: number; conversationsCount: number }[];
+};
diff --git a/packages/model-typings/src/models/ILivechatRoomsModel.ts b/packages/model-typings/src/models/ILivechatRoomsModel.ts
index 68b72be33ba8..20100cbb4f61 100644
--- a/packages/model-typings/src/models/ILivechatRoomsModel.ts
+++ b/packages/model-typings/src/models/ILivechatRoomsModel.ts
@@ -1,4 +1,11 @@
-import type { IMessage, IOmnichannelRoom, IOmnichannelRoomClosingInfo, ISetting, ILivechatVisitor } from '@rocket.chat/core-typings';
+import type {
+ IMessage,
+ IOmnichannelRoom,
+ IOmnichannelRoomClosingInfo,
+ ISetting,
+ ILivechatVisitor,
+ MACStats,
+} from '@rocket.chat/core-typings';
import type { FindCursor, UpdateResult, AggregationCursor, Document, FindOptions, DeleteResult, Filter } from 'mongodb';
import type { FindPaginated } from '..';
@@ -234,4 +241,7 @@ export interface ILivechatRoomsModel extends IBaseModel {
setVisitorInactivityInSecondsById(roomId: string, visitorInactivity: any): Promise;
changeVisitorByRoomId(roomId: string, visitor: { _id: string; username: string; token: string }): Promise;
unarchiveOneById(roomId: string): Promise;
+ markVisitorActiveForPeriod(rid: string, period: string): Promise;
+ getMACStatisticsForPeriod(period: string): Promise;
+ getMACStatisticsBetweenDates(start: Date, end: Date): Promise;
}
diff --git a/packages/model-typings/src/models/ILivechatVisitorsModel.ts b/packages/model-typings/src/models/ILivechatVisitorsModel.ts
index 370db511dadf..5c598c6a6a97 100644
--- a/packages/model-typings/src/models/ILivechatVisitorsModel.ts
+++ b/packages/model-typings/src/models/ILivechatVisitorsModel.ts
@@ -48,4 +48,16 @@ export interface ILivechatVisitorsModel extends IBaseModel {
updateById(_id: string, update: UpdateFilter): Promise;
saveGuestEmailPhoneById(_id: string, emails: string[], phones: string[]): Promise;
+
+ isVisitorActiveOnPeriod(visitorId: string, period: string): Promise;
+
+ markVisitorActiveForPeriod(visitorId: string, period: string): Promise;
+
+ findOneEnabledById(_id: string, options?: FindOptions): Promise;
+
+ disableById(_id: string): Promise;
+
+ findEnabled(query: Filter, options?: FindOptions): FindCursor;
+
+ countVisitorsOnPeriod(period: string): Promise;
}