diff --git a/.changeset/shaggy-clocks-allow.md b/.changeset/shaggy-clocks-allow.md new file mode 100644 index 0000000000000..b422d07d913e6 --- /dev/null +++ b/.changeset/shaggy-clocks-allow.md @@ -0,0 +1,6 @@ +--- +"@rocket.chat/meteor": patch +"@rocket.chat/rest-typings": patch +--- + +Adds deprecation warning on `livechat:removeTag` with new endpoint replacing it; `livechat/tags.remove` diff --git a/apps/meteor/client/omnichannel/tags/useRemoveTag.tsx b/apps/meteor/client/omnichannel/tags/useRemoveTag.tsx index 3b35cdd88b106..9864e0801861c 100644 --- a/apps/meteor/client/omnichannel/tags/useRemoveTag.tsx +++ b/apps/meteor/client/omnichannel/tags/useRemoveTag.tsx @@ -1,6 +1,6 @@ import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import { GenericModal } from '@rocket.chat/ui-client'; -import { useSetModal, useToastMessageDispatch, useRouter, useMethod } from '@rocket.chat/ui-contexts'; +import { useSetModal, useToastMessageDispatch, useRouter, useEndpoint } from '@rocket.chat/ui-contexts'; import { useQueryClient } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; @@ -8,14 +8,14 @@ export const useRemoveTag = () => { const { t } = useTranslation(); const setModal = useSetModal(); const dispatchToastMessage = useToastMessageDispatch(); - const removeTag = useMethod('livechat:removeTag'); + const removeTag = useEndpoint('POST', '/v1/livechat/tags.delete'); const queryClient = useQueryClient(); const router = useRouter(); const handleDeleteTag = useEffectEvent((tagId: string) => { const handleDelete = async () => { try { - await removeTag(tagId); + await removeTag({ id: tagId }); dispatchToastMessage({ type: 'success', message: t('Tag_removed') }); router.navigate('/omnichannel/tags'); queryClient.invalidateQueries({ diff --git a/apps/meteor/ee/app/livechat-enterprise/server/api/tags.ts b/apps/meteor/ee/app/livechat-enterprise/server/api/tags.ts index d9506c24aa5d1..ddaec18bd5063 100644 --- a/apps/meteor/ee/app/livechat-enterprise/server/api/tags.ts +++ b/apps/meteor/ee/app/livechat-enterprise/server/api/tags.ts @@ -1,6 +1,16 @@ +import { + isPOSTLivechatTagsRemoveParams, + POSTLivechatTagsRemoveSuccessResponse, + validateBadRequestErrorResponse, + validateForbiddenErrorResponse, + validateUnauthorizedErrorResponse, +} from '@rocket.chat/rest-typings'; + import { findTags, findTagById } from './lib/tags'; import { API } from '../../../../../app/api/server'; +import type { ExtractRoutesFromAPI } from '../../../../../app/api/server/ApiClass'; import { getPaginationItems } from '../../../../../app/api/server/helpers/getPaginationItems'; +import { LivechatEnterprise } from '../lib/LivechatEnterprise'; API.v1.addRoute( 'livechat/tags', @@ -56,3 +66,40 @@ API.v1.addRoute( }, }, ); + +const livechatTagsEndpoints = API.v1.post( + 'livechat/tags.delete', + { + response: { + 200: POSTLivechatTagsRemoveSuccessResponse, + 400: validateBadRequestErrorResponse, + 401: validateUnauthorizedErrorResponse, + 403: validateForbiddenErrorResponse, + }, + authRequired: true, + permissions: ['manage-livechat-tags'], + license: ['livechat-enterprise'], + body: isPOSTLivechatTagsRemoveParams, + }, + async function action() { + const { id } = this.bodyParams; + try { + await LivechatEnterprise.removeTag(id); + + return API.v1.success(); + } catch (error: unknown) { + if (error instanceof Meteor.Error) { + return API.v1.failure(error.reason); + } + + return API.v1.failure('error-removing-tag'); + } + }, +); + +type LivechatTagsEndpoints = ExtractRoutesFromAPI; + +declare module '@rocket.chat/rest-typings' { + // eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-empty-interface + interface Endpoints extends LivechatTagsEndpoints {} +} diff --git a/apps/meteor/ee/app/livechat-enterprise/server/methods/removeTag.ts b/apps/meteor/ee/app/livechat-enterprise/server/methods/removeTag.ts index 775194dc09c7a..9e97eadaa1a9c 100644 --- a/apps/meteor/ee/app/livechat-enterprise/server/methods/removeTag.ts +++ b/apps/meteor/ee/app/livechat-enterprise/server/methods/removeTag.ts @@ -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' { @@ -14,6 +15,7 @@ declare module '@rocket.chat/ddp-client' { Meteor.methods({ async 'livechat:removeTag'(id) { + methodDeprecationLogger.method('livechat:removeTag', '8.0.0', '/v1/livechat/tags.delete'); const uid = Meteor.userId(); if (!uid || !(await hasPermissionAsync(uid, 'manage-livechat-tags'))) { throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'livechat:removeTag' }); diff --git a/apps/meteor/tests/e2e/utils/omnichannel/tags.ts b/apps/meteor/tests/e2e/utils/omnichannel/tags.ts index ba2a6b43e4d21..a1289d84e8570 100644 --- a/apps/meteor/tests/e2e/utils/omnichannel/tags.ts +++ b/apps/meteor/tests/e2e/utils/omnichannel/tags.ts @@ -10,10 +10,7 @@ type CreateTagParams = { departments?: { departmentId: string }[]; }; -const removeTag = async (api: BaseTest['api'], id: string) => - api.post('/method.call/omnichannel:removeTag', { - message: JSON.stringify({ msg: 'method', id: '33', method: 'livechat:removeTag', params: [id] }), - }); +const removeTag = async (api: BaseTest['api'], id: string) => api.post('/livechat/tags.delete', { id }); export const createTag = async (api: BaseTest['api'], { id = null, name, description = '', departments = [] }: CreateTagParams = {}) => { const response = await api.post('/method.call/livechat:saveTag', { diff --git a/packages/i18n/src/locales/en.i18n.json b/packages/i18n/src/locales/en.i18n.json index 7b4265f5b0463..4735d98dde53e 100644 --- a/packages/i18n/src/locales/en.i18n.json +++ b/packages/i18n/src/locales/en.i18n.json @@ -6232,6 +6232,7 @@ "error-invalid-user": "Invalid user", "error-invalid-username": "Invalid username", "error-invalid-value": "Invalid value", + "error-removing-tag": "Error removing tag", "error-invalid-webhook-response": "The webhook URL responded with a status other than 200", "error-license-user-limit-reached": "The maximum number of users has been reached.", "error-loading-extension-list": "Failed to load extension list", diff --git a/packages/rest-typings/src/v1/omnichannel.ts b/packages/rest-typings/src/v1/omnichannel.ts index 21177c177faef..71de7ed221b83 100644 --- a/packages/rest-typings/src/v1/omnichannel.ts +++ b/packages/rest-typings/src/v1/omnichannel.ts @@ -513,6 +513,36 @@ const LivechatMonitorsListSchema = { export const isLivechatMonitorsListProps = ajv.compile(LivechatMonitorsListSchema); +type POSTLivechatTagsRemoveParams = { + id: string; +}; + +const POSTLivechatTagsRemoveSchema = { + type: 'object', + properties: { + id: { + type: 'string', + }, + }, + required: ['id'], + additionalProperties: false, +}; + +export const isPOSTLivechatTagsRemoveParams = ajv.compile(POSTLivechatTagsRemoveSchema); + +const POSTLivechatTagsRemoveSuccessResponseSchema = { + type: 'object', + properties: { + success: { + type: 'boolean', + enum: [true], + }, + }, + additionalProperties: false, +}; + +export const POSTLivechatTagsRemoveSuccessResponse = ajv.compile(POSTLivechatTagsRemoveSuccessResponseSchema); + type LivechatTagsListProps = PaginatedRequest<{ text: string; viewAll?: 'true' | 'false'; department?: string }, 'name'>; const LivechatTagsListSchema = {