diff --git a/apps/meteor/client/components/GenericError/GenericError.tsx b/apps/meteor/client/components/GenericError/GenericError.tsx
new file mode 100644
index 00000000000..22f9923dea2
--- /dev/null
+++ b/apps/meteor/client/components/GenericError/GenericError.tsx
@@ -0,0 +1,31 @@
+import { Box, States, StatesIcon, StatesTitle, StatesActions, StatesAction } from '@rocket.chat/fuselage';
+import type { Keys as IconName } from '@rocket.chat/icons';
+import { useTranslation } from '@rocket.chat/ui-contexts';
+import React from 'react';
+
+type GenericErrorProps = {
+ icon?: IconName;
+ title?: string;
+ buttonTitle?: string;
+ buttonAction?: () => void;
+};
+
+const GenericError = ({ icon = 'magnifier', title, buttonTitle, buttonAction }: GenericErrorProps) => {
+ const t = useTranslation();
+
+ return (
+
+
+
+ {title || t('Something_went_wrong')}
+ {buttonAction && (
+
+ {buttonTitle || t('Reload_page')}
+
+ )}
+
+
+ );
+};
+
+export default GenericError;
diff --git a/apps/meteor/client/components/GenericError/index.ts b/apps/meteor/client/components/GenericError/index.ts
new file mode 100644
index 00000000000..e38d015fe74
--- /dev/null
+++ b/apps/meteor/client/components/GenericError/index.ts
@@ -0,0 +1 @@
+export { default } from './GenericError';
diff --git a/apps/meteor/client/views/omnichannel/routes.ts b/apps/meteor/client/views/omnichannel/routes.ts
index 9d2ed96e8b1..11de2598e6a 100644
--- a/apps/meteor/client/views/omnichannel/routes.ts
+++ b/apps/meteor/client/views/omnichannel/routes.ts
@@ -128,7 +128,7 @@ registerOmnichannelRoute('/tags/:context?/:id?', {
registerOmnichannelRoute('/triggers/:context?/:id?', {
name: 'omnichannel-triggers',
- component: lazy(() => import('./triggers/TriggersPage')),
+ component: lazy(() => import('./triggers/TriggersRoute')),
});
registerOmnichannelRoute('/current/:id?/:tab?/:context?', {
diff --git a/apps/meteor/client/views/omnichannel/triggers/EditTrigger.tsx b/apps/meteor/client/views/omnichannel/triggers/EditTrigger.tsx
new file mode 100644
index 00000000000..1de0373deb4
--- /dev/null
+++ b/apps/meteor/client/views/omnichannel/triggers/EditTrigger.tsx
@@ -0,0 +1,306 @@
+import type { ILivechatTrigger, ILivechatTriggerCondition, Serialized } from '@rocket.chat/core-typings';
+import type { SelectOption } from '@rocket.chat/fuselage';
+import {
+ FieldGroup,
+ Button,
+ ButtonGroup,
+ Box,
+ Field,
+ FieldLabel,
+ FieldRow,
+ FieldError,
+ TextInput,
+ ToggleSwitch,
+ Select,
+ TextAreaInput,
+} from '@rocket.chat/fuselage';
+import { useUniqueId } from '@rocket.chat/fuselage-hooks';
+import { useToastMessageDispatch, useRouter, useEndpoint, useTranslation } from '@rocket.chat/ui-contexts';
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+import React, { useMemo } from 'react';
+import { Controller, useFieldArray, useForm } from 'react-hook-form';
+
+import {
+ ContextualbarScrollableContent,
+ ContextualbarTitle,
+ ContextualbarFooter,
+ Contextualbar,
+ ContextualbarHeader,
+ ContextualbarClose,
+} from '../../../components/Contextualbar';
+
+const getInitialValues = (triggerData: Serialized | undefined) => ({
+ name: triggerData?.name || '',
+ description: triggerData?.description || '',
+ enabled: triggerData?.enabled || true,
+ runOnce: !!triggerData?.runOnce || false,
+ conditions: triggerData?.conditions.map(({ name, value }) => ({ name: name || 'page-url', value: value || '' })) || [
+ { name: 'page-url' as unknown as ILivechatTriggerCondition['name'], value: '' },
+ ],
+ actions: triggerData?.actions.map(({ name, params }) => ({
+ name: name || '',
+ params: {
+ sender: params?.sender || 'queue',
+ msg: params?.msg || '',
+ name: params?.name || '',
+ },
+ })) || [
+ {
+ name: 'send-message',
+ params: {
+ sender: 'queue',
+ msg: '',
+ name: '',
+ },
+ },
+ ],
+});
+
+type TriggersPayload = {
+ name: string;
+ description: string;
+ enabled: boolean;
+ runOnce: boolean;
+ // In the future, this will be an array
+ conditions: ILivechatTrigger['conditions'];
+ // In the future, this will be an array
+ actions: ILivechatTrigger['actions'];
+};
+
+const EditTrigger = ({ triggerData }: { triggerData?: Serialized }) => {
+ const t = useTranslation();
+ const router = useRouter();
+ const queryClient = useQueryClient();
+ const dispatchToastMessage = useToastMessageDispatch();
+
+ const saveTrigger = useEndpoint('POST', '/v1/livechat/triggers');
+
+ const {
+ control,
+ handleSubmit,
+ formState: { isDirty, errors },
+ watch,
+ } = useForm({ mode: 'onBlur', values: getInitialValues(triggerData) });
+
+ const { fields: conditionsFields } = useFieldArray({
+ control,
+ name: 'conditions',
+ });
+
+ const { fields: actionsFields } = useFieldArray({
+ control,
+ name: 'actions',
+ });
+
+ const { description, conditions, actions } = watch();
+
+ const conditionOptions: SelectOption[] = useMemo(
+ () => [
+ ['page-url', t('Visitor_page_URL')],
+ ['time-on-site', t('Visitor_time_on_site')],
+ ['chat-opened-by-visitor', t('Chat_opened_by_visitor')],
+ ['after-guest-registration', t('After_guest_registration')],
+ ],
+ [t],
+ );
+
+ const conditionValuePlaceholders: { [conditionName: string]: string } = useMemo(
+ () => ({
+ 'page-url': t('Enter_a_regex'),
+ 'time-on-site': t('Time_in_seconds'),
+ }),
+ [t],
+ );
+
+ const senderOptions: SelectOption[] = useMemo(
+ () => [
+ ['queue', t('Impersonate_next_agent_from_queue')],
+ ['custom', t('Custom_agent')],
+ ],
+ [t],
+ );
+
+ const saveTriggerMutation = useMutation({
+ mutationFn: saveTrigger,
+ onSuccess: () => {
+ dispatchToastMessage({ type: 'success', message: t('Saved') });
+ queryClient.invalidateQueries(['livechat-triggers']);
+ router.navigate('/omnichannel/triggers');
+ },
+ onError: (error) => {
+ dispatchToastMessage({ type: 'error', message: error });
+ },
+ });
+
+ const handleSave = async (data: TriggersPayload) => {
+ saveTriggerMutation.mutateAsync({ ...data, _id: triggerData?._id });
+ };
+
+ const formId = useUniqueId();
+ const enabledField = useUniqueId();
+ const runOnceField = useUniqueId();
+ const nameField = useUniqueId();
+ const descriptionField = useUniqueId();
+ const conditionField = useUniqueId();
+ const actionField = useUniqueId();
+ const actionMessageField = useUniqueId();
+
+ return (
+
+
+ {triggerData?._id ? t('Edit_Trigger') : t('New_Trigger')}
+ router.navigate('/omnichannel/triggers')} />
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default EditTrigger;
diff --git a/apps/meteor/client/views/omnichannel/triggers/EditTriggerPage.js b/apps/meteor/client/views/omnichannel/triggers/EditTriggerPage.js
deleted file mode 100644
index cc2edf7b919..00000000000
--- a/apps/meteor/client/views/omnichannel/triggers/EditTriggerPage.js
+++ /dev/null
@@ -1,104 +0,0 @@
-import { FieldGroup, Button, ButtonGroup } from '@rocket.chat/fuselage';
-import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
-import { useToastMessageDispatch, useRoute, useEndpoint, useTranslation } from '@rocket.chat/ui-contexts';
-import React from 'react';
-
-import { ContextualbarScrollableContent, ContextualbarFooter } from '../../../components/Contextualbar';
-import { useForm } from '../../../hooks/useForm';
-import TriggersForm from './TriggersForm';
-
-const getInitialValues = ({
- name,
- description,
- enabled,
- runOnce,
- conditions: [{ name: condName, value: condValue }],
- actions: [
- {
- action: actName,
- params: { sender: actSender, msg: actMsg, name: actSenderName },
- },
- ],
-}) => ({
- name: name ?? '',
- description: description ?? '',
- enabled: !!enabled,
- runOnce: !!runOnce,
- conditions: {
- name: condName ?? 'page-url',
- value: condValue ?? '',
- },
- actions: {
- name: actName ?? '',
- params: {
- sender: actSender ?? 'queue',
- msg: actMsg ?? '',
- name: actSenderName ?? '',
- },
- },
-});
-
-const EditTriggerPage = ({ data, onSave }) => {
- const dispatchToastMessage = useToastMessageDispatch();
- const t = useTranslation();
-
- const router = useRoute('omnichannel-triggers');
-
- const save = useEndpoint('POST', '/v1/livechat/triggers');
-
- const { values, handlers, hasUnsavedChanges } = useForm(getInitialValues(data));
-
- const handleSave = useMutableCallback(async () => {
- try {
- const {
- actions: {
- params: { sender, msg, name },
- },
- ...restValues
- } = values;
- await save({
- _id: data._id,
- ...restValues,
- conditions: [values.conditions],
- actions: [
- {
- name: 'send-message',
- params: {
- sender,
- msg,
- ...(sender === 'custom' && { name }),
- },
- },
- ],
- });
- dispatchToastMessage({ type: 'success', message: t('Saved') });
- onSave();
- router.push({});
- } catch (error) {
- dispatchToastMessage({ type: 'error', message: error });
- }
- });
-
- const { name } = values;
-
- const canSave = name && hasUnsavedChanges;
-
- return (
- <>
-
-
-
-
-
-
-
-
-
-
- >
- );
-};
-
-export default EditTriggerPage;
diff --git a/apps/meteor/client/views/omnichannel/triggers/EditTriggerPageContainer.js b/apps/meteor/client/views/omnichannel/triggers/EditTriggerPageContainer.js
deleted file mode 100644
index 6252ce51c19..00000000000
--- a/apps/meteor/client/views/omnichannel/triggers/EditTriggerPageContainer.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import { Callout } from '@rocket.chat/fuselage';
-import { useTranslation } from '@rocket.chat/ui-contexts';
-import React from 'react';
-
-import PageSkeleton from '../../../components/PageSkeleton';
-import { AsyncStatePhase } from '../../../hooks/useAsyncState';
-import { useEndpointData } from '../../../hooks/useEndpointData';
-import EditTriggerPage from './EditTriggerPage';
-
-const EditTriggerPageContainer = ({ id, onSave }) => {
- const t = useTranslation();
- const { value: data, phase: state } = useEndpointData('/v1/livechat/triggers/:_id', { keys: { _id: id } });
-
- if (state === AsyncStatePhase.LOADING) {
- return ;
- }
-
- if (state === AsyncStatePhase.REJECTED || !data?.trigger) {
- return {t('Error')}: error;
- }
-
- return ;
-};
-
-export default EditTriggerPageContainer;
diff --git a/apps/meteor/client/views/omnichannel/triggers/EditTriggerWithData.tsx b/apps/meteor/client/views/omnichannel/triggers/EditTriggerWithData.tsx
new file mode 100644
index 00000000000..10a54494c4f
--- /dev/null
+++ b/apps/meteor/client/views/omnichannel/triggers/EditTriggerWithData.tsx
@@ -0,0 +1,28 @@
+import type { ILivechatTrigger } from '@rocket.chat/core-typings';
+import { Callout } from '@rocket.chat/fuselage';
+import { useEndpoint, useTranslation } from '@rocket.chat/ui-contexts';
+import { useQuery } from '@tanstack/react-query';
+import React from 'react';
+
+import { ContextualbarSkeleton } from '../../../components/Contextualbar';
+import EditTrigger from './EditTrigger';
+
+const EditTriggerWithData = ({ triggerId }: { triggerId: ILivechatTrigger['_id'] }) => {
+ const t = useTranslation();
+ const getTriggersById = useEndpoint('GET', '/v1/livechat/triggers/:_id', { _id: triggerId });
+ const { data, isLoading, isError } = useQuery(['livechat-getTriggersById', triggerId], async () => getTriggersById(), {
+ refetchOnWindowFocus: false,
+ });
+
+ if (isLoading) {
+ return ;
+ }
+
+ if (isError) {
+ return {t('Error')};
+ }
+
+ return ;
+};
+
+export default EditTriggerWithData;
diff --git a/apps/meteor/client/views/omnichannel/triggers/NewTriggerPage.js b/apps/meteor/client/views/omnichannel/triggers/NewTriggerPage.js
deleted file mode 100644
index 9f696ebe1aa..00000000000
--- a/apps/meteor/client/views/omnichannel/triggers/NewTriggerPage.js
+++ /dev/null
@@ -1,94 +0,0 @@
-import { Button, FieldGroup, ButtonGroup } from '@rocket.chat/fuselage';
-import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
-import { useToastMessageDispatch, useRoute, useEndpoint, useTranslation } from '@rocket.chat/ui-contexts';
-import React, { useMemo } from 'react';
-
-import { ContextualbarScrollableContent, ContextualbarFooter } from '../../../components/Contextualbar';
-import { useForm } from '../../../hooks/useForm';
-import TriggersForm from './TriggersForm';
-
-const NewTriggerPage = ({ onSave }) => {
- const dispatchToastMessage = useToastMessageDispatch();
- const t = useTranslation();
-
- const router = useRoute('omnichannel-triggers');
-
- const save = useEndpoint('POST', '/v1/livechat/triggers');
-
- const { values, handlers } = useForm({
- name: '',
- description: '',
- enabled: true,
- runOnce: false,
- conditions: {
- name: 'page-url',
- value: '',
- },
- actions: {
- name: '',
- params: {
- sender: 'queue',
- msg: '',
- name: '',
- },
- },
- });
-
- const handleSave = useMutableCallback(async () => {
- try {
- const {
- actions: {
- params: { sender, msg, name },
- },
- ...restValues
- } = values;
- await save({
- ...restValues,
- conditions: [values.conditions],
- actions: [
- {
- name: 'send-message',
- params: {
- sender,
- msg,
- ...(sender === 'custom' && { name }),
- },
- },
- ],
- });
- dispatchToastMessage({ type: 'success', message: t('Saved') });
- onSave();
- router.push({});
- } catch (error) {
- dispatchToastMessage({ type: 'error', message: error });
- }
- });
-
- const {
- name,
- actions: {
- params: { msg },
- },
- } = values;
-
- const canSave = useMemo(() => name && msg, [name, msg]);
-
- return (
- <>
-
-
-
-
-
-
-
-
-
-
- >
- );
-};
-
-export default NewTriggerPage;
diff --git a/apps/meteor/client/views/omnichannel/triggers/TriggersForm.stories.tsx b/apps/meteor/client/views/omnichannel/triggers/TriggersForm.stories.tsx
index 37595518279..4bc7fe37c7c 100644
--- a/apps/meteor/client/views/omnichannel/triggers/TriggersForm.stories.tsx
+++ b/apps/meteor/client/views/omnichannel/triggers/TriggersForm.stories.tsx
@@ -1,13 +1,12 @@
import { FieldGroup, Box } from '@rocket.chat/fuselage';
-import { action } from '@storybook/addon-actions';
import type { ComponentMeta, ComponentStory } from '@storybook/react';
import React from 'react';
-import TriggersForm from './TriggersForm';
+import EditTrigger from './EditTrigger';
export default {
- title: 'Omnichannel/TriggersForm',
- component: TriggersForm,
+ title: 'Omnichannel/EditTrigger',
+ component: EditTrigger,
decorators: [
(fn) => (
@@ -15,35 +14,6 @@ export default {
),
],
-} as ComponentMeta;
+} as ComponentMeta;
-export const Default: ComponentStory = (args) => ;
-Default.storyName = 'TriggersForm';
-Default.args = {
- values: {
- name: '',
- description: '',
- enabled: true,
- runOnce: false,
- conditions: {
- name: 'page-url',
- value: '',
- },
- actions: {
- name: '',
- params: {
- sender: 'queue',
- msg: '',
- name: '',
- },
- },
- },
- handlers: {
- handleName: action('handleName'),
- handleDescription: action('handleDescription'),
- handleEnabled: action('handleEnabled'),
- handleRunOnce: action('handleRunOnce'),
- handleConditions: action('handleConditions'),
- handleActions: action('handleActions'),
- },
-};
+export const Default: ComponentStory = (args) => ;
diff --git a/apps/meteor/client/views/omnichannel/triggers/TriggersForm.tsx b/apps/meteor/client/views/omnichannel/triggers/TriggersForm.tsx
deleted file mode 100644
index 7c947605941..00000000000
--- a/apps/meteor/client/views/omnichannel/triggers/TriggersForm.tsx
+++ /dev/null
@@ -1,212 +0,0 @@
-import type { SelectOption } 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';
-import React, { useMemo, useState } from 'react';
-
-import { useComponentDidUpdate } from '../../../hooks/useComponentDidUpdate';
-
-type TriggerConditions = {
- name: string;
- value: string | number;
-};
-
-type TriggerActions = {
- name: string;
- params: {
- sender: string | undefined;
- msg: string;
- name: string;
- };
-};
-
-type TriggersFormProps = {
- values: {
- name: string;
- description: string;
- enabled: boolean;
- runOnce: boolean;
- // In the future, this will be an array
- conditions: TriggerConditions;
- // In the future, this will be an array
- actions: TriggerActions;
- };
- handlers: {
- handleName: (event: FormEvent) => void;
- handleDescription: (event: FormEvent) => void;
- handleEnabled: (event: FormEvent) => void;
- handleRunOnce: (event: FormEvent) => void;
- handleConditions: (value: TriggerConditions) => void;
- handleActions: (value: TriggerActions) => void;
- };
- className?: ComponentProps['className'];
-};
-
-const TriggersForm: FC = ({ values, handlers, className }) => {
- const [nameError, setNameError] = useState('');
- const [msgError, setMsgError] = useState('');
- const t = useTranslation();
- const { name, description, enabled, runOnce, conditions, actions } = values;
-
- const { handleName, handleDescription, handleEnabled, handleRunOnce, handleConditions, handleActions } = handlers;
-
- const { name: conditionName, value: conditionValue } = conditions;
-
- const {
- params: { sender: actionSender, msg: actionMsg, name: actionAgentName },
- } = actions;
-
- const conditionOptions: SelectOption[] = useMemo(
- () => [
- ['page-url', t('Visitor_page_URL')],
- ['time-on-site', t('Visitor_time_on_site')],
- ['chat-opened-by-visitor', t('Chat_opened_by_visitor')],
- ['after-guest-registration', t('After_guest_registration')],
- ],
- [t],
- );
-
- const conditionValuePlaceholders: { [conditionName: string]: string } = useMemo(
- () => ({
- 'page-url': t('Enter_a_regex'),
- 'time-on-site': t('Time_in_seconds'),
- }),
- [t],
- );
-
- const conditionValuePlaceholder = conditionValuePlaceholders[conditionName];
-
- const senderOptions: SelectOption[] = useMemo(
- () => [
- ['queue', t('Impersonate_next_agent_from_queue')],
- ['custom', t('Custom_agent')],
- ],
- [t],
- );
-
- const handleConditionName = useMutableCallback((name) => {
- handleConditions({
- name,
- value: '',
- });
- });
-
- const handleConditionValue = useMutableCallback(({ currentTarget: { value } }) => {
- handleConditions({
- ...conditions,
- value,
- });
- });
-
- const handleActionAgentName = useMutableCallback(({ currentTarget: { value: name } }) => {
- handleActions({
- ...actions,
- params: {
- ...actions.params,
- name,
- },
- });
- });
-
- const handleActionSender = useMutableCallback((sender) => {
- handleActions({
- ...actions,
- params: {
- ...actions.params,
- sender,
- },
- });
- });
-
- const handleActionMessage = useMutableCallback(({ currentTarget: { value: msg } }) => {
- handleActions({
- ...actions,
- params: {
- ...actions.params,
- msg,
- },
- });
- });
- useComponentDidUpdate(() => {
- setNameError(!name ? t('The_field_is_required', t('Name')) : '');
- }, [t, name]);
- useComponentDidUpdate(() => {
- setMsgError(!actionMsg ? t('The_field_is_required', t('Message')) : '');
- }, [t, actionMsg]);
- return (
- <>
-
-
- {t('Enabled')}
-
-
-
-
-
-
-
- {t('Run_only_once_for_each_visitor')}
-
-
-
-
-
-
- {t('Name')}*
-
-
-
- {nameError}
-
-
- {t('Description')}
-
-
-
-
-
- {t('Condition')}
-
-
-
- {conditionValuePlaceholder && (
-
-
-
- )}
-
-
- {t('Action')}
-
-
-
-
-
-
- {actionSender === 'custom' && (
-
-
-
- )}
-
-
-
- {msgError}
-
- >
- );
-};
-
-export default TriggersForm;
diff --git a/apps/meteor/client/views/omnichannel/triggers/TriggersPage.tsx b/apps/meteor/client/views/omnichannel/triggers/TriggersPage.tsx
index 457f12b39a7..79eea71b623 100644
--- a/apps/meteor/client/views/omnichannel/triggers/TriggersPage.tsx
+++ b/apps/meteor/client/views/omnichannel/triggers/TriggersPage.tsx
@@ -1,60 +1,30 @@
import { Button } from '@rocket.chat/fuselage';
-import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
-import { useRoute, useRouteParameter, usePermission, useTranslation } from '@rocket.chat/ui-contexts';
-import React, { useRef, useCallback } from 'react';
+import { useRouteParameter, useRouter, useTranslation } from '@rocket.chat/ui-contexts';
+import React from 'react';
-import { Contextualbar, ContextualbarTitle, ContextualbarHeader, ContextualbarClose } from '../../../components/Contextualbar';
import Page from '../../../components/Page';
-import NotAuthorizedPage from '../../notAuthorized/NotAuthorizedPage';
-import EditTriggerPageContainer from './EditTriggerPageContainer';
-import NewTriggerPage from './NewTriggerPage';
+import EditTrigger from './EditTrigger';
+import EditTriggerWithData from './EditTriggerWithData';
import TriggersTable from './TriggersTable';
const TriggersPage = () => {
const t = useTranslation();
const id = useRouteParameter('id');
const context = useRouteParameter('context');
- const router = useRoute('omnichannel-triggers');
- const canViewTriggers = usePermission('view-livechat-triggers');
-
- const reload = useRef(() => null);
-
- const handleReload = useCallback(() => {
- reload.current();
- }, []);
-
- const handleAdd = useMutableCallback(() => {
- router.push({ context: 'new' });
- });
-
- const handleCloseContextualbar = useMutableCallback(() => {
- router.push({});
- });
-
- if (!canViewTriggers) {
- return ;
- }
+ const router = useRouter();
return (
-
+
-
+
- {context && (
-
-
- {t('Trigger')}
-
-
- {context === 'edit' && }
- {context === 'new' && }
-
- )}
+ {context === 'edit' && id && }
+ {context === 'new' && }
);
};
diff --git a/apps/meteor/client/views/omnichannel/triggers/TriggersRoute.tsx b/apps/meteor/client/views/omnichannel/triggers/TriggersRoute.tsx
new file mode 100644
index 00000000000..7cf2d06bd3b
--- /dev/null
+++ b/apps/meteor/client/views/omnichannel/triggers/TriggersRoute.tsx
@@ -0,0 +1,17 @@
+import { usePermission } from '@rocket.chat/ui-contexts';
+import React from 'react';
+
+import NotAuthorizedPage from '../../notAuthorized/NotAuthorizedPage';
+import TriggersPage from './TriggersPage';
+
+const TriggersRoute = () => {
+ const canViewTriggers = usePermission('view-livechat-triggers');
+
+ if (!canViewTriggers) {
+ return ;
+ }
+
+ return ;
+};
+
+export default TriggersRoute;
diff --git a/apps/meteor/client/views/omnichannel/triggers/TriggersTable.tsx b/apps/meteor/client/views/omnichannel/triggers/TriggersTable.tsx
index 729ef41d435..8c0ea0213da 100644
--- a/apps/meteor/client/views/omnichannel/triggers/TriggersTable.tsx
+++ b/apps/meteor/client/views/omnichannel/triggers/TriggersTable.tsx
@@ -1,11 +1,11 @@
-import { Callout, Pagination } from '@rocket.chat/fuselage';
+import { Pagination } from '@rocket.chat/fuselage';
import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
import { useTranslation, useEndpoint, useRouter } from '@rocket.chat/ui-contexts';
import { useQuery, hashQueryKey } from '@tanstack/react-query';
-import type { MutableRefObject } from 'react';
-import React, { useEffect, useMemo, useState } from 'react';
+import React, { useMemo, useState } from 'react';
-import GenericNoResults from '../../../components/GenericNoResults/GenericNoResults';
+import GenericError from '../../../components/GenericError';
+import GenericNoResults from '../../../components/GenericNoResults';
import {
GenericTable,
GenericTableHeader,
@@ -16,7 +16,7 @@ import {
import { usePagination } from '../../../components/GenericTable/hooks/usePagination';
import TriggersRow from './TriggersRow';
-const TriggersTable = ({ reload }: { reload: MutableRefObject<() => void> }) => {
+const TriggersTable = () => {
const t = useTranslation();
const router = useRouter();
@@ -34,20 +34,12 @@ const TriggersTable = ({ reload }: { reload: MutableRefObject<() => void> }) =>
const [defaultQuery] = useState(hashQueryKey([query]));
const queryHasChanged = defaultQuery !== hashQueryKey([query]);
- useEffect(() => {
- reload.current = refetch;
- }, [reload, refetch]);
-
- if (isError) {
- return {t('Error')};
- }
-
const headers = (
<>
{t('Name')}
{t('Description')}
{t('Enabled')}
- {t('Remove')}
+
>
);
@@ -94,6 +86,7 @@ const TriggersTable = ({ reload }: { reload: MutableRefObject<() => void> }) =>
/>
>
)}
+ {isError && }
>
);
};
diff --git a/apps/meteor/tests/e2e/omnichannel/omnichannel-triggers.spec.ts b/apps/meteor/tests/e2e/omnichannel/omnichannel-triggers.spec.ts
index 9db221723eb..d1adc22d7bb 100644
--- a/apps/meteor/tests/e2e/omnichannel/omnichannel-triggers.spec.ts
+++ b/apps/meteor/tests/e2e/omnichannel/omnichannel-triggers.spec.ts
@@ -6,7 +6,7 @@ import { Users } from '../fixtures/userStates';
import { OmnichannelLiveChat, HomeOmnichannel } from '../page-objects';
import { test, expect } from '../utils/test';
-test.describe.serial('Omnichannel Triggers', () => {
+test.describe.parallel('omnichannel-triggers', () => {
let triggersName: string;
let triggerMessage: string;
let poLiveChat: OmnichannelLiveChat;
diff --git a/apps/meteor/tests/e2e/page-objects/omnichannel-triggers.ts b/apps/meteor/tests/e2e/page-objects/omnichannel-triggers.ts
index a90171f7442..2ac39a4b52f 100644
--- a/apps/meteor/tests/e2e/page-objects/omnichannel-triggers.ts
+++ b/apps/meteor/tests/e2e/page-objects/omnichannel-triggers.ts
@@ -17,33 +17,17 @@ export class OmnichannelTriggers {
}
get inputName(): Locator {
- return this.page.locator('[placeholder="Name"]');
+ return this.page.locator('input[name="name"]');
}
get inputDescription(): Locator {
- return this.page.locator('[placeholder="Description"]');
- }
-
- get addTime(): Locator {
- return this.page.locator('[placeholder="Time in seconds"]');
- }
-
- get impersonateAgentListBox(): Locator {
- return this.page.locator('ol[role="listbox"] >> text=Impersonate next agent from queue');
- }
-
- get textArea(): Locator {
- return this.page.locator('textarea');
+ return this.page.locator('input[name="description"]');
}
get btnSave(): Locator {
return this.page.locator('button >> text="Save"');
}
- get firstRowInTable() {
- return this.page.locator('table tr:first-child td:first-child');
- }
-
firstRowInTriggerTable(triggersName1: string) {
return this.page.locator(`text="${triggersName1}"`);
}
@@ -56,14 +40,6 @@ export class OmnichannelTriggers {
return this.toastMessage.locator('role=button');
}
- get inputSearch() {
- return this.page.locator('[placeholder="Search"]');
- }
-
- get pageTitle() {
- return this.page.locator('[data-qa-type="PageHeader-title"]');
- }
-
get btnDeletefirstRowInTable() {
return this.page.locator('table tr:first-child td:last-child button');
}
@@ -76,33 +52,33 @@ export class OmnichannelTriggers {
return this.page.locator('text=Trigger removed');
}
- get inputCondition(): Locator {
- return this.page.locator('button', { has: this.page.locator('select[name="condition"]') });
+ get conditionLabel(): Locator {
+ return this.page.locator('label >> text="Condition"')
}
get inputConditionValue(): Locator {
- return this.page.locator('input[name="conditionValue"]');
+ return this.page.locator('input[name="conditions.0.value"]');
}
- get inputSender(): Locator {
- return this.page.locator('button', { has: this.page.locator('select[name="sender"]') });
+ get actionLabel(): Locator {
+ return this.page.locator('label >> text="Action"')
}
get inputAgentName(): Locator {
- return this.page.locator('input[name="agentName"]');
+ return this.page.locator('input[name="actions.0.params.name"]');
}
get inputTriggerMessage(): Locator {
- return this.page.locator('textarea[name="triggerMessage"]');
+ return this.page.locator('textarea[name="actions.0.params.msg"]');
}
async selectCondition(condition: string) {
- await this.inputCondition.click();
+ await this.conditionLabel.click();
await this.page.locator(`li.rcx-option[data-key="${condition}"]`).click();
}
async selectSender(sender: 'queue' | 'custom') {
- await this.inputSender.click();
+ await this.actionLabel.click();
await this.page.locator(`li.rcx-option[data-key="${sender}"]`).click();
}
diff --git a/packages/rest-typings/src/v1/omnichannel.ts b/packages/rest-typings/src/v1/omnichannel.ts
index fcdbf17bb94..1d2f7a7469b 100644
--- a/packages/rest-typings/src/v1/omnichannel.ts
+++ b/packages/rest-typings/src/v1/omnichannel.ts
@@ -3615,7 +3615,7 @@ export type OmnichannelEndpoints = {
POST: (params: POSTLivechatTriggersParams) => void;
};
'/v1/livechat/triggers/:_id': {
- GET: () => { trigger: ILivechatTrigger | null };
+ GET: () => { trigger: ILivechatTrigger };
DELETE: () => void;
};
'/v1/livechat/rooms': {