Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BREAK] Move Multiple Department Creation to EE & [NEW] Department Archive #27753

Merged
merged 71 commits into from
Feb 13, 2023
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
985b025
Move save department functionality to EE
sampaiodiego Jan 13, 2023
4e24aba
[FE] Move Departments to EE
MartinSchoeler Jan 13, 2023
ff865e3
Merge branch 'departments-to-ee' into move-save-department-ee
MartinSchoeler Jan 13, 2023
d61b219
Fix weird caching issue
MartinSchoeler Jan 13, 2023
984da48
Fix TS & Better error message
MartinSchoeler Jan 16, 2023
88c6dd5
Tests and small changes
MartinSchoeler Jan 16, 2023
085c803
Better wording
MartinSchoeler Jan 16, 2023
c9a5070
Merge branch 'develop' into move-save-department-ee
MartinSchoeler Jan 16, 2023
317bd12
Fix reviews & ee tests
MartinSchoeler Jan 16, 2023
6ea0021
Merge branch 'move-save-department-ee' of https://github.com/RocketCh…
MartinSchoeler Jan 16, 2023
df4d8e7
fix review again
MartinSchoeler Jan 16, 2023
050b0c2
Fix reviews
MartinSchoeler Jan 16, 2023
1919d18
reviews
MartinSchoeler Jan 16, 2023
49231b8
Merge branch 'develop' into move-save-department-ee
MartinSchoeler Jan 16, 2023
f89b05d
Fix wrong conditional
MartinSchoeler Jan 17, 2023
31da816
Merge branch 'move-save-department-ee' of https://github.com/RocketCh…
MartinSchoeler Jan 17, 2023
cf29e81
Merge branch 'develop' into move-save-department-ee
tassoevan Jan 18, 2023
f8f1e65
Fix tests
MartinSchoeler Jan 19, 2023
fca41f8
Lint
MartinSchoeler Jan 19, 2023
a7a1c3d
Move department tests to ee
MartinSchoeler Jan 20, 2023
6500401
Merge branch 'develop' into move-save-department-ee
MartinSchoeler Jan 20, 2023
61ad52d
Update NewDepartment.tsx
MartinSchoeler Jan 20, 2023
e8502c8
I love typescript ™
MartinSchoeler Jan 20, 2023
aa408af
Update apps/meteor/tests/data/livechat/rooms.ts
MartinSchoeler Jan 23, 2023
8a96b75
Merge branch 'develop' into move-save-department-ee
MartinSchoeler Jan 23, 2023
1ef34e9
Fix TS
MartinSchoeler Jan 26, 2023
0713f98
Merge branch 'develop' into move-save-department-ee
MartinSchoeler Jan 26, 2023
9be3049
Merge branch 'develop' into move-save-department-ee
MartinSchoeler Jan 30, 2023
40cc2d5
Merge branch 'develop' into move-save-department-ee
MartinSchoeler Jan 31, 2023
f5cab82
add jsdoc
MartinSchoeler Jan 31, 2023
235b605
Merge branch 'move-save-department-ee' of https://github.com/RocketCh…
MartinSchoeler Jan 31, 2023
8ad8a06
Remove extra skip
MartinSchoeler Jan 31, 2023
6f9c1f2
remove wrong field
MartinSchoeler Jan 31, 2023
dbdfffd
TS fixes
MartinSchoeler Jan 31, 2023
55457ec
Fix TS
MartinSchoeler Jan 31, 2023
5f783b5
Move some tests to EE for now
MartinSchoeler Feb 1, 2023
d4edfdf
Merge branch 'develop' into move-save-department-ee
MartinSchoeler Feb 1, 2023
8535bd7
Use correct image
MartinSchoeler Feb 3, 2023
56be13d
Fix reviews on test
MartinSchoeler Feb 3, 2023
e1b7494
Merge branch 'develop' into move-save-department-ee
MartinSchoeler Feb 3, 2023
dfa6298
Reviews
MartinSchoeler Feb 6, 2023
94a81ab
Review
MartinSchoeler Feb 6, 2023
0c107c2
Merge branch 'develop' into move-save-department-ee
MartinSchoeler Feb 6, 2023
dd77129
update wording
MartinSchoeler Feb 6, 2023
fafaaeb
Merge branch 'move-save-department-ee' of https://github.com/RocketCh…
MartinSchoeler Feb 6, 2023
2f5007c
Merge branch 'develop' into move-save-department-ee
MartinSchoeler Feb 7, 2023
1b6b47b
Merge branch 'develop' into move-save-department-ee
MartinSchoeler Feb 7, 2023
6ea6659
Update raw model
KevLehman Feb 7, 2023
8422b8b
Merge branch 'move-save-department-ee' of github.com:RocketChat/Rocke…
KevLehman Feb 7, 2023
d39c13d
lint
MartinSchoeler Feb 7, 2023
0d3df9a
Remove empty line
MartinSchoeler Feb 7, 2023
ce5dab8
Small wording & link changes to modal
MartinSchoeler Feb 8, 2023
27f0d33
Merge branch 'develop' into move-save-department-ee
KevLehman Feb 8, 2023
fc420e0
Merge branch 'develop' into move-save-department-ee
MartinSchoeler Feb 9, 2023
c77addb
[NEW] Department Archivation (#27966)
MartinSchoeler Feb 9, 2023
ca8a7ca
Merge branch 'develop' into move-save-department-ee
MartinSchoeler Feb 9, 2023
6d059b2
Fix typo
MartinSchoeler Feb 10, 2023
d17a769
Merge branch 'develop' into move-save-department-ee
MartinSchoeler Feb 10, 2023
fafc64c
Fix reviews & pagination
MartinSchoeler Feb 10, 2023
680ad26
Merge branch 'move-save-department-ee' of https://github.com/RocketCh…
MartinSchoeler Feb 10, 2023
38c5694
Chore: Add archived department tests (#27992)
MartinSchoeler Feb 10, 2023
b5a75a5
Improve coverage
MartinSchoeler Feb 10, 2023
0ca3edc
Merge branch 'develop' of github.com:RocketChat/Rocket.Chat into move…
tassoevan Feb 11, 2023
679c67f
Refactor minor pet peeves
tassoevan Feb 11, 2023
0282109
Refactor minor pet peeves
tassoevan Feb 11, 2023
e199349
Refactor minor pet peeves
tassoevan Feb 11, 2023
d604602
Merge branch 'develop' into move-save-department-ee
murtaza98 Feb 13, 2023
d22906e
Fix error on edit forward
MartinSchoeler Feb 13, 2023
ebbfb21
Merge branch 'move-save-department-ee' of https://github.com/RocketCh…
MartinSchoeler Feb 13, 2023
cff00b7
Fix some reviews
MartinSchoeler Feb 13, 2023
b84d8ed
Merge branch 'develop' into move-save-department-ee
kodiakhq[bot] Feb 13, 2023
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
5 changes: 3 additions & 2 deletions apps/meteor/app/livechat/imports/server/rest/departments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
findDepartmentsBetweenIds,
findDepartmentAgents,
} from '../../../server/api/lib/departments';
import { LivechatEnterprise } from '../../../../../ee/app/livechat-enterprise/server/lib/LivechatEnterprise';

API.v1.addRoute(
'livechat/department',
Expand Down Expand Up @@ -54,7 +55,7 @@ API.v1.addRoute(
});

const agents = this.bodyParams.agents ? { upsert: this.bodyParams.agents } : {};
const department = Livechat.saveDepartment(null, this.bodyParams.department, agents);
const department = await LivechatEnterprise.saveDepartment(null, this.bodyParams.department, agents);

if (department) {
return API.v1.success({
Expand Down Expand Up @@ -117,7 +118,7 @@ API.v1.addRoute(

let success;
if (permissionToSave) {
success = Livechat.saveDepartment(_id, department);
success = await LivechatEnterprise.saveDepartment(_id, department);
}

if (success && agents && permissionToAddAgents) {
Expand Down
68 changes: 0 additions & 68 deletions apps/meteor/app/livechat/server/lib/Livechat.js
Original file line number Diff line number Diff line change
Expand Up @@ -1043,74 +1043,6 @@ export const Livechat = {
return updateDepartmentAgents(_id, departmentAgents, department.enabled);
},

saveDepartment(_id, departmentData, departmentAgents) {
check(_id, Match.Maybe(String));

const defaultValidations = {
enabled: Boolean,
name: String,
description: Match.Optional(String),
showOnRegistration: Boolean,
email: String,
showOnOfflineForm: Boolean,
requestTagBeforeClosingChat: Match.Optional(Boolean),
chatClosingTags: Match.Optional([String]),
fallbackForwardDepartment: Match.Optional(String),
};

// The Livechat Form department support addition/custom fields, so those fields need to be added before validating
Object.keys(departmentData).forEach((field) => {
if (!defaultValidations.hasOwnProperty(field)) {
defaultValidations[field] = Match.OneOf(String, Match.Integer, Boolean);
}
});

check(departmentData, defaultValidations);
check(
departmentAgents,
Match.Maybe({
upsert: Match.Maybe(Array),
remove: Match.Maybe(Array),
}),
);

const { requestTagBeforeClosingChat, chatClosingTags, fallbackForwardDepartment } = departmentData;
if (requestTagBeforeClosingChat && (!chatClosingTags || chatClosingTags.length === 0)) {
throw new Meteor.Error(
'error-validating-department-chat-closing-tags',
'At least one closing tag is required when the department requires tag(s) on closing conversations.',
{ method: 'livechat:saveDepartment' },
);
}

if (_id) {
const department = LivechatDepartment.findOneById(_id);
if (!department) {
throw new Meteor.Error('error-department-not-found', 'Department not found', {
method: 'livechat:saveDepartment',
});
}
}

if (fallbackForwardDepartment === _id) {
throw new Meteor.Error(
'error-fallback-department-circular',
'Cannot save department. Circular reference between fallback department and department',
);
}

if (fallbackForwardDepartment && !LivechatDepartment.findOneById(fallbackForwardDepartment)) {
throw new Meteor.Error('error-fallback-department-not-found', 'Fallback department not found', { method: 'livechat:saveDepartment' });
}

const departmentDB = LivechatDepartment.createOrUpdateDepartment(_id, departmentData);
if (departmentDB && departmentAgents) {
updateDepartmentAgents(departmentDB._id, departmentAgents, departmentDB.enabled);
}

return departmentDB;
},

saveAgentInfo(_id, agentData, agentDepartments) {
check(_id, Match.Maybe(String));
check(agentData, Object);
Expand Down
6 changes: 3 additions & 3 deletions apps/meteor/app/livechat/server/methods/saveDepartment.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { Meteor } from 'meteor/meteor';

import { hasPermission } from '../../../authorization';
import { Livechat } from '../lib/Livechat';
import { LivechatEnterprise } from '../../../../ee/app/livechat-enterprise/server/lib/LivechatEnterprise';

Meteor.methods({
'livechat:saveDepartment'(_id, departmentData, departmentAgents) {
async 'livechat:saveDepartment'(_id, departmentData, departmentAgents) {
if (!Meteor.userId() || !hasPermission(Meteor.userId(), 'manage-livechat-departments')) {
throw new Meteor.Error('error-not-allowed', 'Not allowed', {
method: 'livechat:saveDepartment',
});
}

return Livechat.saveDepartment(_id, departmentData, { upsert: departmentAgents });
return LivechatEnterprise.saveDepartment(_id, departmentData, { upsert: departmentAgents });
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { Button, Modal, Box } from '@rocket.chat/fuselage';
import { useOutsideClick } from '@rocket.chat/fuselage-hooks';
import { useRoute, useTranslation } from '@rocket.chat/ui-contexts';
import type { ReactElement } from 'react';
import React, { useRef } from 'react';

import { hasPermission } from '../../../../app/authorization/client';
import { useUpgradeTabParams } from '../../../views/hooks/useUpgradeTabParams';

const EnterpriseDepartmentsModal = ({ closeModal }: { closeModal: () => void }): ReactElement => {
const t = useTranslation();
const upgradeRoute = useRoute('upgrade');
const departmentsRoute = useRoute('omnichannel-departments');
const { tabType, trialEndDate } = useUpgradeTabParams();
const ref = useRef<HTMLDivElement>(null);
const upgradeNowClick = (): void => {
tabType && upgradeRoute.push({ type: tabType }, trialEndDate ? { trialEndDate } : undefined);
closeModal();
};

const onClose = (): void => {
departmentsRoute.push({});
closeModal();
};

useOutsideClick([ref], onClose);

return (
<>
MartinSchoeler marked this conversation as resolved.
Show resolved Hide resolved
<Modal data-qa-id='enterprise-departments-modal' ref={ref}>
<Modal.Header>
<Modal.HeaderText>
<Modal.Tagline>{t('Enterprise_capability')}</Modal.Tagline>
<Modal.Title>{t('Departments')}</Modal.Title>
</Modal.HeaderText>
<Modal.Close onClick={onClose} data-qa='modal-close' />
</Modal.Header>
<Modal.Content fontScale='p2'>
<Modal.HeroImage src='/images/departments.svg' />
<Box fontSize={20} fontWeight={700} lineHeight={28} mbe={28}>
{t('Enterprise_Departments_title')}
</Box>
{tabType === 'go-fully-featured' || tabType === 'go-fully-featured-registered' || tabType === 'upgrade-your-plan'
? t('Enterprise_Departments_description_upgrade')
: t('Enterprise_Departments_description_free_trial')}
</Modal.Content>
<Modal.Footer>
{hasPermission('view-statistics') ? (
<Modal.FooterControllers>
<Button is='a' href='https://rocket.chat/contact' external onClick={onClose} data-qa-id='btn-talk-to-sales'>
{t('Talk_to_sales')}
</Button>
<Button onClick={upgradeNowClick} primary data-qa-id='upgrade-now'>
{tabType === 'go-fully-featured' || tabType === 'go-fully-featured-registered' || tabType === 'upgrade-your-plan'
? t('Start_free_trial')
: t('Learn_more')}
</Button>
</Modal.FooterControllers>
) : (
MartinSchoeler marked this conversation as resolved.
Show resolved Hide resolved
<Box display='flex' width='100%' justifyContent='space-between' alignItems='center'>
Talk to your workspace admin about enabling departments.
<Button onClick={onClose} data-qa='button-close'>
{t('Close')}
</Button>
</Box>
)}
</Modal.Footer>
</Modal>
</>
);
};

export default EnterpriseDepartmentsModal;
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import { Table } from '@rocket.chat/fuselage';
import { useDebouncedValue, useMutableCallback } from '@rocket.chat/fuselage-hooks';
import { useRouteParameter, useRoute, usePermission, useTranslation } from '@rocket.chat/ui-contexts';
import React, { useMemo, useCallback, useState } from 'react';
import { useRouteParameter, useRoute, usePermission, useTranslation, useEndpoint } from '@rocket.chat/ui-contexts';
import { useQuery } from '@tanstack/react-query';
import React, { useMemo, useCallback, useState, useRef } from 'react';

import GenericTable from '../../../components/GenericTable';
import { useEndpointData } from '../../../hooks/useEndpointData';
import NotAuthorizedPage from '../../notAuthorized/NotAuthorizedPage';
import DepartmentsPage from './DepartmentsPage';
import EditDepartment from './EditDepartment';
import EditDepartmentWithData from './EditDepartmentWithData';
import NewDepartment from './NewDepartment';
import RemoveDepartmentButton from './RemoveDepartmentButton';

const sortDir = (sortDir) => (sortDir === 'asc' ? 1 : -1);

const useQuery = ({ text, itemsPerPage, current }, [column, direction], onlyMyDepartments) =>
const useDepartmentsQuery = ({ text, itemsPerPage, current }, [column, direction], onlyMyDepartments) =>
MartinSchoeler marked this conversation as resolved.
Show resolved Hide resolved
useMemo(
() => ({
fields: JSON.stringify({ name: 1, username: 1, emails: 1, avatarETag: 1 }),
Expand Down Expand Up @@ -44,11 +44,16 @@ function DepartmentsRoute() {
const debouncedParams = useDebouncedValue(params, 500);
const debouncedSort = useDebouncedValue(sort, 500);
const onlyMyDepartments = true;
const query = useQuery(debouncedParams, debouncedSort, onlyMyDepartments);
const departmentsRoute = useRoute('omnichannel-departments');
const context = useRouteParameter('context');
const id = useRouteParameter('id');

const refetchRef = useRef(() => undefined);

const handleRefetch = useCallback(() => {
refetchRef.current();
}, [refetchRef]);

MartinSchoeler marked this conversation as resolved.
Show resolved Hide resolved
const onHeaderClick = useMutableCallback((id) => {
const [sortBy, sortDirection] = sort;

Expand All @@ -67,7 +72,23 @@ function DepartmentsRoute() {
}),
);

const { value: data = {}, reload } = useEndpointData('/v1/livechat/department', { params: query });
const query = {
onlyMyDepartments,
text: debouncedParams.text,
offset: debouncedParams.current,
count: debouncedParams.itemsPerPage,
sort: JSON.stringify({
[debouncedSort.column]: sortDir(debouncedSort.direction),
usernames: debouncedSort.column === 'name' ? sortDir(debouncedSort.direction) : undefined,
}),
fields: JSON.stringify({ name: 1, username: 1, emails: 1, avatarETag: 1 }),
};

const getDepartments = useEndpoint('GET', '/v1/livechat/department');

const { data, refetch } = useQuery(['getDepartments', query], async () => getDepartments(query));
MartinSchoeler marked this conversation as resolved.
Show resolved Hide resolved

const reload = useCallback(() => refetch(), [refetch]);

const header = useMemo(
() =>
Expand Down Expand Up @@ -122,18 +143,18 @@ function DepartmentsRoute() {
<Table.Cell withTruncatedText>{numAgents || '0'}</Table.Cell>
<Table.Cell withTruncatedText>{enabled ? t('Yes') : t('No')}</Table.Cell>
<Table.Cell withTruncatedText>{showOnRegistration ? t('Yes') : t('No')}</Table.Cell>
{canRemoveDepartments && <RemoveDepartmentButton _id={_id} reload={reload} />}
{canRemoveDepartments && <RemoveDepartmentButton _id={_id} reload={reload} refetch={handleRefetch} />}
</Table.Row>
),
[canRemoveDepartments, onRowClick, t, reload],
[canRemoveDepartments, handleRefetch, onRowClick, reload, t],
);

if (!canViewDepartments) {
return <NotAuthorizedPage />;
}

if (context === 'new') {
return <EditDepartment id={id} reload={reload} title={t('New_Department')} />;
return <NewDepartment id={id} reload={reload} refetchRef={refetchRef} title={t('New_Department')} />;
}

if (context === 'edit') {
Expand All @@ -146,7 +167,7 @@ function DepartmentsRoute() {
params={params}
onHeaderClick={onHeaderClick}
data={data}
useQuery={useQuery}
useQuery={useDepartmentsQuery}
reload={reload}
header={header}
renderRow={renderRow}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { useEndpoint, useTranslation } from '@rocket.chat/ui-contexts';
import { useQuery } from '@tanstack/react-query';
import type { MutableRefObject } from 'react';
import React, { useEffect } from 'react';

import { useHasLicenseModule } from '../../../../ee/client/hooks/useHasLicenseModule';
import PageSkeleton from '../../../components/PageSkeleton';
import EditDepartment from './EditDepartment';
import UpgradeDepartments from './UpgradeDepartments';

type NewDepartmentProps = {
id: string;
reload: () => void;
refetchRef: MutableRefObject<() => void>;
};

const NewDepartment = ({ id, reload, refetchRef }: NewDepartmentProps) => {
const getDepartments = useEndpoint('GET', '/v1/livechat/department');
const hasLicense = useHasLicenseModule('livechat-enterprise');
const { data, refetch, isLoading } = useQuery(['getDepartments'], async () => getDepartments());
MartinSchoeler marked this conversation as resolved.
Show resolved Hide resolved
MartinSchoeler marked this conversation as resolved.
Show resolved Hide resolved

useEffect(() => {
refetchRef.current = refetch;
}, [refetchRef, refetch]);

const t = useTranslation();

if (isLoading || hasLicense === 'loading') {
return <PageSkeleton />;
}
if (!hasLicense && data?.total && data.total >= 1) {
return <UpgradeDepartments />;
}
// TODO: remove allowedToForwardData and data props once the EditDepartment component is migrated to TS
return <EditDepartment id={id} reload={reload} title={t('New_Department')} allowedToForwardData={undefined} data={undefined} />;
};

export default NewDepartment;
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import React from 'react';
import GenericModal from '../../../components/GenericModal';
import { useEndpointAction } from '../../../hooks/useEndpointAction';

function RemoveDepartmentButton({ _id, reload }) {
function RemoveDepartmentButton({ _id, reload, refetch }) {
MartinSchoeler marked this conversation as resolved.
Show resolved Hide resolved
const deleteAction = useEndpointAction('DELETE', '/v1/livechat/department/:_id', { keys: { _id } });
const setModal = useSetModal();
const dispatchToastMessage = useToastMessageDispatch();
Expand All @@ -16,6 +16,7 @@ function RemoveDepartmentButton({ _id, reload }) {
const result = await deleteAction();
if (result.success === true) {
reload();
refetch();
}
});

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { useSetModal } from '@rocket.chat/ui-contexts';
import React, { useEffect } from 'react';

import EnterpriseDepartmentsModal from '../../../components/Omnichannel/modals/EnterpriseDepartmentsModal';
import PageSkeleton from '../../../components/PageSkeleton';

const UpgradeDepartments = () => {
const setModal = useSetModal();

useEffect(() => setModal(<EnterpriseDepartmentsModal closeModal={(): void => setModal(null)} />), [setModal]);
return <PageSkeleton />;
};

export default UpgradeDepartments;
Loading