Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
7b20fa8
chore: adds deprecation warning to livechat:addMonitor
lucas-a-pelegrino Sep 25, 2025
d30f6dc
chore: adds new endpoint for adding monitors
lucas-a-pelegrino Sep 25, 2025
34f96d7
tests: updates tests to use monitors.save endpoint
lucas-a-pelegrino Sep 25, 2025
28ce1bf
chore: updates client to use monitors.save endpoint instead of the de…
lucas-a-pelegrino Sep 25, 2025
ec6ff33
Merge branch 'develop' of github.com:RocketChat/Rocket.Chat into chor…
lucas-a-pelegrino Sep 25, 2025
673eebd
docs: adds changeset
lucas-a-pelegrino Sep 25, 2025
48629e7
chore: adds a deprecation warning on livechat:removeMonitor
lucas-a-pelegrino Sep 25, 2025
882bcf8
chore: adds new endpoint livechat/monitors.remove
lucas-a-pelegrino Sep 25, 2025
22a7719
fix: lint error
lucas-a-pelegrino Sep 25, 2025
a927186
Merge branch 'chore/v7/CTZ-74' of github.com:RocketChat/Rocket.Chat i…
lucas-a-pelegrino Sep 25, 2025
c41b058
Merge branch 'chore/v7/CTZ-74' into chore/v7/CTZ-77
lucas-a-pelegrino Sep 25, 2025
719315a
chore: adds new endpoint livechat/monitors.remove
lucas-a-pelegrino Sep 25, 2025
3e1c252
tests: updates tests to use livechat/monitors.remove endpoint
lucas-a-pelegrino Sep 25, 2025
3da66f3
chore: updates client to use the new endpoint
lucas-a-pelegrino Sep 25, 2025
b95ad1c
tests: updates removeMonitor helper
lucas-a-pelegrino Sep 25, 2025
73bbe6a
fix: lint error
lucas-a-pelegrino Oct 15, 2025
a57af43
Merge branch 'develop' of github.com:RocketChat/Rocket.Chat into chor…
lucas-a-pelegrino Nov 26, 2025
bc4f8b1
chore: refactors endpoint name to have .delete suffix
lucas-a-pelegrino Nov 26, 2025
14463dd
chore: adds minor improvements
lucas-a-pelegrino Nov 27, 2025
4100cf4
fix: deleteMonitor endpoint
lucas-a-pelegrino Dec 1, 2025
96a5f75
chore: fixes deprecation warning
lucas-a-pelegrino Dec 1, 2025
36d685a
Merge branch 'develop' into chore/v7/CTZ-77
lucas-a-pelegrino Dec 1, 2025
c936d33
chore: adds required prop in response schema
lucas-a-pelegrino Dec 1, 2025
90bb4ce
Merge remote-tracking branch 'origin/chore/v7/CTZ-77' into chore/v7/C…
lucas-a-pelegrino Dec 1, 2025
ae4b8dc
Merge branch 'develop' into chore/v7/CTZ-77
kodiakhq[bot] Dec 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
} from '@rocket.chat/fuselage';
import { useDebouncedValue } from '@rocket.chat/fuselage-hooks';
import { UserAutoComplete, GenericModal } from '@rocket.chat/ui-client';
import { useTranslation, useToastMessageDispatch, useMethod, useEndpoint, useSetModal } from '@rocket.chat/ui-contexts';
import { useTranslation, useToastMessageDispatch, useEndpoint, useSetModal } from '@rocket.chat/ui-contexts';
import { useMutation, useQuery, hashKey, useQueryClient } from '@tanstack/react-query';
import { useMemo, useState } from 'react';

Expand Down Expand Up @@ -47,8 +47,7 @@ const MonitorsTable = () => {

const getMonitors = useEndpoint('GET', '/v1/livechat/monitors');

// TODO: implement endpoints for monitors add/remove
const removeMonitor = useMethod('livechat:removeMonitor');
const deleteMonitor = useEndpoint('POST', '/v1/livechat/monitors.delete');
const addMonitor = useEndpoint('POST', '/v1/livechat/monitors.create');

const { current, itemsPerPage, setItemsPerPage: onSetItemsPerPage, setCurrent: onSetCurrent, ...paginationProps } = pagination;
Expand Down Expand Up @@ -99,7 +98,7 @@ const MonitorsTable = () => {
const handleRemove = (username: string) => {
const onDeleteMonitor = async () => {
try {
await removeMonitor(username);
await deleteMonitor({ username });
dispatchToastMessage({ type: 'success', message: t('Monitor_removed') });
} catch (error) {
dispatchToastMessage({ type: 'error', message: error });
Expand Down
74 changes: 55 additions & 19 deletions apps/meteor/ee/app/livechat-enterprise/server/api/monitors.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import type { ILivechatMonitor } from '@rocket.chat/core-typings';
import {
isPOSTLivechatMonitorCreateRequest,
isPOSTLivechatMonitorsDeleteRequest,
POSTLivechatMonitorsCreateSuccessResponse,
POSTLivechatMonitorsDeleteSuccessResponse,
validateBadRequestErrorResponse,
validateForbiddenErrorResponse,
validateUnauthorizedErrorResponse,
Expand Down Expand Up @@ -60,28 +62,62 @@ API.v1.addRoute(
},
);

const livechatMonitorsEndpoints = API.v1.post(
'livechat/monitors.create',
{
response: {
200: POSTLivechatMonitorsCreateSuccessResponse,
400: validateBadRequestErrorResponse,
401: validateUnauthorizedErrorResponse,
403: validateForbiddenErrorResponse,
const livechatMonitorsEndpoints = API.v1
.post(
'livechat/monitors.create',
{
response: {
200: POSTLivechatMonitorsCreateSuccessResponse,
400: validateBadRequestErrorResponse,
401: validateUnauthorizedErrorResponse,
403: validateForbiddenErrorResponse,
},
authRequired: true,
permissionsRequired: ['manage-livechat-monitors'],
license: ['livechat-enterprise'],
body: isPOSTLivechatMonitorCreateRequest,
},
authRequired: true,
permissionsRequired: ['manage-livechat-monitors'],
license: ['livechat-enterprise'],
body: isPOSTLivechatMonitorCreateRequest,
},
async function action() {
const { username } = this.bodyParams;
async function action() {
const { username } = this.bodyParams;

const result = await LivechatEnterprise.addMonitor(username);
const result = await LivechatEnterprise.addMonitor(username);

return API.v1.success(result);
},
);
return API.v1.success(result);
},
)
.post(
'livechat/monitors.delete',
{
response: {
200: POSTLivechatMonitorsDeleteSuccessResponse,
400: validateBadRequestErrorResponse,
401: validateUnauthorizedErrorResponse,
403: validateForbiddenErrorResponse,
},
authRequired: true,
permissionsRequired: ['manage-livechat-monitors'],
license: ['livechat-enterprise'],
body: isPOSTLivechatMonitorsDeleteRequest,
},
async function action() {
const { username } = this.bodyParams;

try {
const result = await LivechatEnterprise.removeMonitor(username);
if (!result) {
return API.v1.failure('error-removing-monitor');
}

return API.v1.success();
} catch (error: unknown) {
if (error instanceof Meteor.Error) {
return API.v1.failure(error.reason);
}

return API.v1.failure('error-removing-monitor');
}
},
);

type LivechatMonitorsEndpoints = ExtractRoutesFromAPI<typeof livechatMonitorsEndpoints>;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { check } from 'meteor/check';
import { Meteor } from 'meteor/meteor';

import { hasPermissionAsync } from '../../../../../app/authorization/server/functions/hasPermission';
import { methodDeprecationLogger } from '../../../../../app/lib/server/lib/deprecationWarningLogger';
import { LivechatEnterprise } from '../lib/LivechatEnterprise';

declare module '@rocket.chat/ddp-client' {
Expand All @@ -14,6 +15,7 @@ declare module '@rocket.chat/ddp-client' {

Meteor.methods<ServerMethods>({
async 'livechat:removeMonitor'(username) {
methodDeprecationLogger.method('livechat:removeMonitor', '8.0.0', '/v1/livechat/monitors.delete');
const uid = Meteor.userId();
if (!uid || !(await hasPermissionAsync(uid, 'manage-livechat-monitors'))) {
throw new Meteor.Error('error-not-allowed', 'Not allowed', {
Expand Down
7 changes: 2 additions & 5 deletions apps/meteor/tests/e2e/utils/omnichannel/monitors.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import type { BaseTest } from '../test';

const removeMonitor = async (api: BaseTest['api'], id: string) =>
api.post('/method.call/livechat:removeMonitor', {
message: JSON.stringify({ msg: 'method', id: '33', method: 'livechat:removeMonitor', params: [id] }),
});
const deleteMonitor = async (api: BaseTest['api'], username: string) => api.post('/livechat/monitors.delete', { username });

export const createMonitor = async (api: BaseTest['api'], username: string) => {
const response = await api.post('/livechat/monitors.create', { username });
Expand All @@ -17,6 +14,6 @@ export const createMonitor = async (api: BaseTest['api'], username: string) => {
return {
response,
data,
delete: async () => removeMonitor(api, data.username),
delete: async () => deleteMonitor(api, data.username),
};
};
33 changes: 8 additions & 25 deletions apps/meteor/tests/end-to-end/api/livechat/22-monitors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { ILivechatDepartment, IUser } from '@rocket.chat/core-typings';
import { expect } from 'chai';
import { before, it, describe, after } from 'mocha';

import { getCredentials, api, request, methodCall, credentials } from '../../../data/api-data';
import { getCredentials, api, request, credentials } from '../../../data/api-data';
import { addOrRemoveAgentFromDepartment, createDepartment } from '../../../data/livechat/department';
import {
createAgent,
Expand Down Expand Up @@ -111,37 +111,20 @@ type TestUser = { user: IUser; credentials: Credentials };
});

it('should remove a monitor', async () => {
const { body } = await request
.post(methodCall(`livechat:removeMonitor`))
.set(credentials)
.send({
message: JSON.stringify({
method: 'livechat:removeMonitor',
params: [user.username],
id: '101',
msg: 'method',
}),
})
.expect(200);
const { body } = await request.post(api('livechat/monitors.delete')).set(credentials).send({ username: user.username }).expect(200);

expect(body.success).to.be.true;
});

it('should not fail when trying to remove a monitor that does not exist', async () => {
it('should fail when trying to remove a monitor that does not exist', async () => {
const { body } = await request
.post(methodCall(`livechat:removeMonitor`))
.post(api('livechat/monitors.delete'))
.set(credentials)
.send({
message: JSON.stringify({
method: 'livechat:removeMonitor',
params: [user.username],
id: '101',
msg: 'method',
}),
})
.expect(200);
.send({ username: 'some-random-username' })
.expect(400);

expect(body.success).to.be.true;
expect(body.success).to.be.false;
expect(body).to.have.property('error').to.be.equal('Invalid user');
});
});

Expand Down
28 changes: 28 additions & 0 deletions packages/rest-typings/src/v1/omnichannel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,34 @@ export const POSTLivechatMonitorsCreateSuccessResponse = ajv.compile<POSTLivecha
POSTLivechatMonitorsCreateSuccessSchema,
);

type POSTLivechatMonitorsDeleteRequest = {
username: string;
};

const POSTLivechatMonitorsDeleteRequestSchema = {
type: 'object',
properties: {
username: {
type: 'string',
},
},
required: ['username'],
additionalProperties: false,
};

export const isPOSTLivechatMonitorsDeleteRequest = ajv.compile<POSTLivechatMonitorsDeleteRequest>(POSTLivechatMonitorsDeleteRequestSchema);

const POSTLivechatMonitorsDeleteSuccessSchema = {
type: 'object',
properties: {
success: { type: 'boolean', enum: [true] },
},
required: ['success'],
additionalProperties: false,
};

export const POSTLivechatMonitorsDeleteSuccessResponse = ajv.compile<void>(POSTLivechatMonitorsDeleteSuccessSchema);

type POSTLivechatTagsRemoveParams = {
id: string;
};
Expand Down
Loading