feat: update tool-chain to latest (#7975)

Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
This commit is contained in:
Shivam Mishra
2023-09-27 14:02:34 +05:30
committed by GitHub
parent e8b7e791a5
commit a88d155dd7
162 changed files with 3566 additions and 2884 deletions

View File

@@ -6,7 +6,7 @@ module.exports = {
'plugin:storybook/recommended', 'plugin:storybook/recommended',
], ],
parserOptions: { parserOptions: {
parser: 'babel-eslint', parser: '@babel/eslint-parser',
ecmaVersion: 2020, ecmaVersion: 2020,
sourceType: 'module', sourceType: 'module',
}, },
@@ -24,13 +24,16 @@ module.exports = {
'jsx-a11y/label-has-for': 'off', 'jsx-a11y/label-has-for': 'off',
'jsx-a11y/anchor-is-valid': 'off', 'jsx-a11y/anchor-is-valid': 'off',
'import/no-unresolved': 'off', 'import/no-unresolved': 'off',
'vue/html-indent': 'off',
'vue/multi-word-component-names': 'off',
'vue/max-attributes-per-line': [ 'vue/max-attributes-per-line': [
'error', 'error',
{ {
singleline: 20, singleline: {
max: 20,
},
multiline: { multiline: {
max: 1, max: 1,
allowFirstLine: false,
}, },
}, },
], ],
@@ -47,6 +50,7 @@ module.exports = {
}, },
], ],
'vue/no-v-html': 'off', 'vue/no-v-html': 'off',
'vue/component-definition-name-casing': 'off',
'vue/singleline-html-element-content-newline': 'off', 'vue/singleline-html-element-content-newline': 'off',
'import/extensions': ['off'], 'import/extensions': ['off'],
'no-console': 'error', 'no-console': 'error',

View File

@@ -111,10 +111,8 @@ export default {
this.$store.dispatch('setActiveAccount', { this.$store.dispatch('setActiveAccount', {
accountId: this.currentAccountId, accountId: this.currentAccountId,
}); });
const { const { locale, latest_chatwoot_version: latestChatwootVersion } =
locale, this.getAccount(this.currentAccountId);
latest_chatwoot_version: latestChatwootVersion,
} = this.getAccount(this.currentAccountId);
const { pubsub_token: pubsubToken } = this.currentUser || {}; const { pubsub_token: pubsubToken } = this.currentUser || {};
this.setLocale(locale); this.setLocale(locale);
this.updateRTLDirectionView(locale); this.updateRTLDirectionView(locale);

View File

@@ -15,9 +15,8 @@ class ApiClient {
// eslint-disable-next-line class-methods-use-this // eslint-disable-next-line class-methods-use-this
get accountIdFromRoute() { get accountIdFromRoute() {
const isInsideAccountScopedURLs = window.location.pathname.includes( const isInsideAccountScopedURLs =
'/app/accounts' window.location.pathname.includes('/app/accounts');
);
if (isInsideAccountScopedURLs) { if (isInsideAccountScopedURLs) {
return window.location.pathname.split('/')[3]; return window.location.pathname.split('/')[3];

View File

@@ -53,6 +53,7 @@ class ContactAPI extends ApiClient {
return axios.get(requestURL); return axios.get(requestURL);
} }
// eslint-disable-next-line default-param-last
filter(page = 1, sortAttr = 'name', queryPayload) { filter(page = 1, sortAttr = 'name', queryPayload) {
let requestURL = `${this.url}/filter?${buildContactParams(page, sortAttr)}`; let requestURL = `${this.url}/filter?${buildContactParams(page, sortAttr)}`;
return axios.post(requestURL, queryPayload); return axios.post(requestURL, queryPayload);

View File

@@ -1,6 +1,5 @@
import accountAPI from '../account'; import accountAPI from '../account';
import ApiClient from '../../ApiClient'; import ApiClient from '../../ApiClient';
import describeWithAPIMock from '../../specs/apiSpecHelper';
describe('#enterpriseAccountAPI', () => { describe('#enterpriseAccountAPI', () => {
it('creates correct instance', () => { it('creates correct instance', () => {
@@ -13,17 +12,33 @@ describe('#enterpriseAccountAPI', () => {
expect(accountAPI).toHaveProperty('checkout'); expect(accountAPI).toHaveProperty('checkout');
}); });
describeWithAPIMock('API calls', context => { describe('API calls', () => {
const originalAxios = window.axios;
const axiosMock = {
post: jest.fn(() => Promise.resolve()),
get: jest.fn(() => Promise.resolve()),
patch: jest.fn(() => Promise.resolve()),
delete: jest.fn(() => Promise.resolve()),
};
beforeEach(() => {
window.axios = axiosMock;
});
afterEach(() => {
window.axios = originalAxios;
});
it('#checkout', () => { it('#checkout', () => {
accountAPI.checkout(); accountAPI.checkout();
expect(context.axiosMock.post).toHaveBeenCalledWith( expect(axiosMock.post).toHaveBeenCalledWith(
'/enterprise/api/v1/checkout' '/enterprise/api/v1/checkout'
); );
}); });
it('#subscription', () => { it('#subscription', () => {
accountAPI.subscription(); accountAPI.subscription();
expect(context.axiosMock.post).toHaveBeenCalledWith( expect(axiosMock.post).toHaveBeenCalledWith(
'/enterprise/api/v1/subscription' '/enterprise/api/v1/subscription'
); );
}); });

View File

@@ -31,6 +31,7 @@ class ReportsAPI extends ApiClient {
}); });
} }
// eslint-disable-next-line default-param-last
getSummary(since, until, type = 'account', id, groupBy, businessHours) { getSummary(since, until, type = 'account', id, groupBy, businessHours) {
return axios.get(`${this.url}/summary`, { return axios.get(`${this.url}/summary`, {
params: { params: {

View File

@@ -1,6 +1,5 @@
import accountAPI from '../account'; import accountAPI from '../account';
import ApiClient from '../ApiClient'; import ApiClient from '../ApiClient';
import describeWithAPIMock from './apiSpecHelper';
describe('#accountAPI', () => { describe('#accountAPI', () => {
it('creates correct instance', () => { it('creates correct instance', () => {
@@ -13,12 +12,28 @@ describe('#accountAPI', () => {
expect(accountAPI).toHaveProperty('createAccount'); expect(accountAPI).toHaveProperty('createAccount');
}); });
describeWithAPIMock('API calls', context => { describe('API calls', () => {
const originalAxios = window.axios;
const axiosMock = {
post: jest.fn(() => Promise.resolve()),
get: jest.fn(() => Promise.resolve()),
patch: jest.fn(() => Promise.resolve()),
delete: jest.fn(() => Promise.resolve()),
};
beforeEach(() => {
window.axios = axiosMock;
});
afterEach(() => {
window.axios = originalAxios;
});
it('#createAccount', () => { it('#createAccount', () => {
accountAPI.createAccount({ accountAPI.createAccount({
name: 'Chatwoot', name: 'Chatwoot',
}); });
expect(context.axiosMock.post).toHaveBeenCalledWith('/api/v1/accounts', { expect(axiosMock.post).toHaveBeenCalledWith('/api/v1/accounts', {
name: 'Chatwoot', name: 'Chatwoot',
}); });
}); });

View File

@@ -1,6 +1,5 @@
import accountActionsAPI from '../accountActions'; import accountActionsAPI from '../accountActions';
import ApiClient from '../ApiClient'; import ApiClient from '../ApiClient';
import describeWithAPIMock from './apiSpecHelper';
describe('#ContactsAPI', () => { describe('#ContactsAPI', () => {
it('creates correct instance', () => { it('creates correct instance', () => {
@@ -8,10 +7,26 @@ describe('#ContactsAPI', () => {
expect(accountActionsAPI).toHaveProperty('merge'); expect(accountActionsAPI).toHaveProperty('merge');
}); });
describeWithAPIMock('API calls', context => { describe('API calls', () => {
const originalAxios = window.axios;
const axiosMock = {
post: jest.fn(() => Promise.resolve()),
get: jest.fn(() => Promise.resolve()),
patch: jest.fn(() => Promise.resolve()),
delete: jest.fn(() => Promise.resolve()),
};
beforeEach(() => {
window.axios = axiosMock;
});
afterEach(() => {
window.axios = originalAxios;
});
it('#merge', () => { it('#merge', () => {
accountActionsAPI.merge(1, 2); accountActionsAPI.merge(1, 2);
expect(context.axiosMock.post).toHaveBeenCalledWith( expect(axiosMock.post).toHaveBeenCalledWith(
'/api/v1/actions/contact_merge', '/api/v1/actions/contact_merge',
{ {
base_contact_id: 1, base_contact_id: 1,

View File

@@ -1,27 +0,0 @@
function apiSpecHelper() {
beforeEach(() => {
this.originalAxios = window.axios;
this.axiosMock = {
post: jest.fn(() => Promise.resolve()),
get: jest.fn(() => Promise.resolve()),
patch: jest.fn(() => Promise.resolve()),
delete: jest.fn(() => Promise.resolve()),
};
window.axios = this.axiosMock;
});
afterEach(() => {
window.axios = this.originalAxios;
});
}
// https://stackoverflow.com/a/59344023/3901856
const sharedWrapper = describe('sharedWrapper', () => {});
export default function describeWithAPIMock(skillName, testFn) {
return describe(skillName, function configureContext() {
function Context() {}
Context.prototype = sharedWrapper.ctx;
this.ctx = new Context();
apiSpecHelper.call(this);
testFn.call(this, this);
});
}

View File

@@ -1,6 +1,5 @@
import articlesAPI from '../helpCenter/articles'; import articlesAPI from '../helpCenter/articles';
import ApiClient from 'dashboard/api/helpCenter/portals'; import ApiClient from 'dashboard/api/helpCenter/portals';
import describeWithAPIMock from './apiSpecHelper';
describe('#PortalAPI', () => { describe('#PortalAPI', () => {
it('creates correct instance', () => { it('creates correct instance', () => {
@@ -12,7 +11,23 @@ describe('#PortalAPI', () => {
expect(articlesAPI).toHaveProperty('delete'); expect(articlesAPI).toHaveProperty('delete');
expect(articlesAPI).toHaveProperty('getArticles'); expect(articlesAPI).toHaveProperty('getArticles');
}); });
describeWithAPIMock('API calls', context => { describe('API calls', () => {
const originalAxios = window.axios;
const axiosMock = {
post: jest.fn(() => Promise.resolve()),
get: jest.fn(() => Promise.resolve()),
patch: jest.fn(() => Promise.resolve()),
delete: jest.fn(() => Promise.resolve()),
};
beforeEach(() => {
window.axios = axiosMock;
});
afterEach(() => {
window.axios = originalAxios;
});
it('#getArticles', () => { it('#getArticles', () => {
articlesAPI.getArticles({ articlesAPI.getArticles({
pageNumber: 1, pageNumber: 1,
@@ -21,30 +36,62 @@ describe('#PortalAPI', () => {
status: 'published', status: 'published',
author_id: '1', author_id: '1',
}); });
expect(context.axiosMock.get).toHaveBeenCalledWith( expect(axiosMock.get).toHaveBeenCalledWith(
'/api/v1/portals/room-rental/articles?page=1&locale=en-US&status=published&author_id=1' '/api/v1/portals/room-rental/articles?page=1&locale=en-US&status=published&author_id=1'
); );
}); });
}); });
describeWithAPIMock('API calls', context => { describe('API calls', () => {
const originalAxios = window.axios;
const axiosMock = {
post: jest.fn(() => Promise.resolve()),
get: jest.fn(() => Promise.resolve()),
patch: jest.fn(() => Promise.resolve()),
delete: jest.fn(() => Promise.resolve()),
};
beforeEach(() => {
window.axios = axiosMock;
});
afterEach(() => {
window.axios = originalAxios;
});
it('#getArticle', () => { it('#getArticle', () => {
articlesAPI.getArticle({ articlesAPI.getArticle({
id: 1, id: 1,
portalSlug: 'room-rental', portalSlug: 'room-rental',
}); });
expect(context.axiosMock.get).toHaveBeenCalledWith( expect(axiosMock.get).toHaveBeenCalledWith(
'/api/v1/portals/room-rental/articles/1' '/api/v1/portals/room-rental/articles/1'
); );
}); });
}); });
describeWithAPIMock('API calls', context => { describe('API calls', () => {
const originalAxios = window.axios;
const axiosMock = {
post: jest.fn(() => Promise.resolve()),
get: jest.fn(() => Promise.resolve()),
patch: jest.fn(() => Promise.resolve()),
delete: jest.fn(() => Promise.resolve()),
};
beforeEach(() => {
window.axios = axiosMock;
});
afterEach(() => {
window.axios = originalAxios;
});
it('#updateArticle', () => { it('#updateArticle', () => {
articlesAPI.updateArticle({ articlesAPI.updateArticle({
articleId: 1, articleId: 1,
portalSlug: 'room-rental', portalSlug: 'room-rental',
articleObj: { title: 'Update shipping address' }, articleObj: { title: 'Update shipping address' },
}); });
expect(context.axiosMock.patch).toHaveBeenCalledWith( expect(axiosMock.patch).toHaveBeenCalledWith(
'/api/v1/portals/room-rental/articles/1', '/api/v1/portals/room-rental/articles/1',
{ {
title: 'Update shipping address', title: 'Update shipping address',
@@ -52,13 +99,29 @@ describe('#PortalAPI', () => {
); );
}); });
}); });
describeWithAPIMock('API calls', context => { describe('API calls', () => {
const originalAxios = window.axios;
const axiosMock = {
post: jest.fn(() => Promise.resolve()),
get: jest.fn(() => Promise.resolve()),
patch: jest.fn(() => Promise.resolve()),
delete: jest.fn(() => Promise.resolve()),
};
beforeEach(() => {
window.axios = axiosMock;
});
afterEach(() => {
window.axios = originalAxios;
});
it('#deleteArticle', () => { it('#deleteArticle', () => {
articlesAPI.deleteArticle({ articlesAPI.deleteArticle({
articleId: 1, articleId: 1,
portalSlug: 'room-rental', portalSlug: 'room-rental',
}); });
expect(context.axiosMock.delete).toHaveBeenCalledWith( expect(axiosMock.delete).toHaveBeenCalledWith(
'/api/v1/portals/room-rental/articles/1' '/api/v1/portals/room-rental/articles/1'
); );
}); });

View File

@@ -1,18 +1,30 @@
import assignableAgentsAPI from '../assignableAgents'; import assignableAgentsAPI from '../assignableAgents';
import describeWithAPIMock from './apiSpecHelper';
describe('#AssignableAgentsAPI', () => { describe('#AssignableAgentsAPI', () => {
describeWithAPIMock('API calls', context => { describe('API calls', () => {
const originalAxios = window.axios;
const axiosMock = {
post: jest.fn(() => Promise.resolve()),
get: jest.fn(() => Promise.resolve()),
patch: jest.fn(() => Promise.resolve()),
delete: jest.fn(() => Promise.resolve()),
};
beforeEach(() => {
window.axios = axiosMock;
});
afterEach(() => {
window.axios = originalAxios;
});
it('#getAssignableAgents', () => { it('#getAssignableAgents', () => {
assignableAgentsAPI.get([1]); assignableAgentsAPI.get([1]);
expect(context.axiosMock.get).toHaveBeenCalledWith( expect(axiosMock.get).toHaveBeenCalledWith('/api/v1/assignable_agents', {
'/api/v1/assignable_agents', params: {
{ inbox_ids: [1],
params: { },
inbox_ids: [1], });
},
}
);
}); });
}); });
}); });

View File

@@ -1,6 +1,5 @@
import fbChannel from '../../channel/fbChannel'; import fbChannel from '../../channel/fbChannel';
import ApiClient from '../../ApiClient'; import ApiClient from '../../ApiClient';
import describeWithAPIMock from '../apiSpecHelper';
describe('#FBChannel', () => { describe('#FBChannel', () => {
it('creates correct instance', () => { it('creates correct instance', () => {
@@ -11,10 +10,26 @@ describe('#FBChannel', () => {
expect(fbChannel).toHaveProperty('update'); expect(fbChannel).toHaveProperty('update');
expect(fbChannel).toHaveProperty('delete'); expect(fbChannel).toHaveProperty('delete');
}); });
describeWithAPIMock('API calls', context => { describe('API calls', () => {
const originalAxios = window.axios;
const axiosMock = {
post: jest.fn(() => Promise.resolve()),
get: jest.fn(() => Promise.resolve()),
patch: jest.fn(() => Promise.resolve()),
delete: jest.fn(() => Promise.resolve()),
};
beforeEach(() => {
window.axios = axiosMock;
});
afterEach(() => {
window.axios = originalAxios;
});
it('#create', () => { it('#create', () => {
fbChannel.create({ omniauthToken: 'ASFM131CSF@#@$', appId: 'chatwoot' }); fbChannel.create({ omniauthToken: 'ASFM131CSF@#@$', appId: 'chatwoot' });
expect(context.axiosMock.post).toHaveBeenCalledWith( expect(axiosMock.post).toHaveBeenCalledWith(
'/api/v1/callbacks/register_facebook_page', '/api/v1/callbacks/register_facebook_page',
{ {
omniauthToken: 'ASFM131CSF@#@$', omniauthToken: 'ASFM131CSF@#@$',
@@ -27,7 +42,7 @@ describe('#FBChannel', () => {
omniauthToken: 'ASFM131CSF@#@$', omniauthToken: 'ASFM131CSF@#@$',
inboxId: 1, inboxId: 1,
}); });
expect(context.axiosMock.post).toHaveBeenCalledWith( expect(axiosMock.post).toHaveBeenCalledWith(
'/api/v1/callbacks/reauthorize_page', '/api/v1/callbacks/reauthorize_page',
{ {
omniauth_token: 'ASFM131CSF@#@$', omniauth_token: 'ASFM131CSF@#@$',

View File

@@ -1,6 +1,5 @@
import contactAPI, { buildContactParams } from '../contacts'; import contactAPI, { buildContactParams } from '../contacts';
import ApiClient from '../ApiClient'; import ApiClient from '../ApiClient';
import describeWithAPIMock from './apiSpecHelper';
describe('#ContactsAPI', () => { describe('#ContactsAPI', () => {
it('creates correct instance', () => { it('creates correct instance', () => {
@@ -15,56 +14,67 @@ describe('#ContactsAPI', () => {
expect(contactAPI).toHaveProperty('destroyAvatar'); expect(contactAPI).toHaveProperty('destroyAvatar');
}); });
describeWithAPIMock('API calls', context => { describe('API calls', () => {
const originalAxios = window.axios;
const axiosMock = {
post: jest.fn(() => Promise.resolve()),
get: jest.fn(() => Promise.resolve()),
patch: jest.fn(() => Promise.resolve()),
delete: jest.fn(() => Promise.resolve()),
};
beforeEach(() => {
window.axios = axiosMock;
});
afterEach(() => {
window.axios = originalAxios;
});
it('#get', () => { it('#get', () => {
contactAPI.get(1, 'name', 'customer-support'); contactAPI.get(1, 'name', 'customer-support');
expect(context.axiosMock.get).toHaveBeenCalledWith( expect(axiosMock.get).toHaveBeenCalledWith(
'/api/v1/contacts?include_contact_inboxes=false&page=1&sort=name&labels[]=customer-support' '/api/v1/contacts?include_contact_inboxes=false&page=1&sort=name&labels[]=customer-support'
); );
}); });
it('#getConversations', () => { it('#getConversations', () => {
contactAPI.getConversations(1); contactAPI.getConversations(1);
expect(context.axiosMock.get).toHaveBeenCalledWith( expect(axiosMock.get).toHaveBeenCalledWith(
'/api/v1/contacts/1/conversations' '/api/v1/contacts/1/conversations'
); );
}); });
it('#getContactableInboxes', () => { it('#getContactableInboxes', () => {
contactAPI.getContactableInboxes(1); contactAPI.getContactableInboxes(1);
expect(context.axiosMock.get).toHaveBeenCalledWith( expect(axiosMock.get).toHaveBeenCalledWith(
'/api/v1/contacts/1/contactable_inboxes' '/api/v1/contacts/1/contactable_inboxes'
); );
}); });
it('#getContactLabels', () => { it('#getContactLabels', () => {
contactAPI.getContactLabels(1); contactAPI.getContactLabels(1);
expect(context.axiosMock.get).toHaveBeenCalledWith( expect(axiosMock.get).toHaveBeenCalledWith('/api/v1/contacts/1/labels');
'/api/v1/contacts/1/labels'
);
}); });
it('#updateContactLabels', () => { it('#updateContactLabels', () => {
const labels = ['support-query']; const labels = ['support-query'];
contactAPI.updateContactLabels(1, labels); contactAPI.updateContactLabels(1, labels);
expect(context.axiosMock.post).toHaveBeenCalledWith( expect(axiosMock.post).toHaveBeenCalledWith('/api/v1/contacts/1/labels', {
'/api/v1/contacts/1/labels', labels,
{ });
labels,
}
);
}); });
it('#search', () => { it('#search', () => {
contactAPI.search('leads', 1, 'date', 'customer-support'); contactAPI.search('leads', 1, 'date', 'customer-support');
expect(context.axiosMock.get).toHaveBeenCalledWith( expect(axiosMock.get).toHaveBeenCalledWith(
'/api/v1/contacts/search?include_contact_inboxes=false&page=1&sort=date&q=leads&labels[]=customer-support' '/api/v1/contacts/search?include_contact_inboxes=false&page=1&sort=date&q=leads&labels[]=customer-support'
); );
}); });
it('#destroyCustomAttributes', () => { it('#destroyCustomAttributes', () => {
contactAPI.destroyCustomAttributes(1, ['cloudCustomer']); contactAPI.destroyCustomAttributes(1, ['cloudCustomer']);
expect(context.axiosMock.post).toHaveBeenCalledWith( expect(axiosMock.post).toHaveBeenCalledWith(
'/api/v1/contacts/1/destroy_custom_attributes', '/api/v1/contacts/1/destroy_custom_attributes',
{ {
custom_attributes: ['cloudCustomer'], custom_attributes: ['cloudCustomer'],
@@ -75,7 +85,7 @@ describe('#ContactsAPI', () => {
it('#importContacts', () => { it('#importContacts', () => {
const file = 'file'; const file = 'file';
contactAPI.importContacts(file); contactAPI.importContacts(file);
expect(context.axiosMock.post).toHaveBeenCalledWith( expect(axiosMock.post).toHaveBeenCalledWith(
'/api/v1/contacts/import', '/api/v1/contacts/import',
expect.any(FormData), expect.any(FormData),
{ {
@@ -96,7 +106,7 @@ describe('#ContactsAPI', () => {
], ],
}; };
contactAPI.filter(1, 'name', queryPayload); contactAPI.filter(1, 'name', queryPayload);
expect(context.axiosMock.post).toHaveBeenCalledWith( expect(axiosMock.post).toHaveBeenCalledWith(
'/api/v1/contacts/filter?include_contact_inboxes=false&page=1&sort=name', '/api/v1/contacts/filter?include_contact_inboxes=false&page=1&sort=name',
queryPayload queryPayload
); );
@@ -104,7 +114,7 @@ describe('#ContactsAPI', () => {
it('#destroyAvatar', () => { it('#destroyAvatar', () => {
contactAPI.destroyAvatar(1); contactAPI.destroyAvatar(1);
expect(context.axiosMock.delete).toHaveBeenCalledWith( expect(axiosMock.delete).toHaveBeenCalledWith(
'/api/v1/contacts/1/avatar' '/api/v1/contacts/1/avatar'
); );
}); });

View File

@@ -1,6 +1,5 @@
import conversationsAPI from '../conversations'; import conversationsAPI from '../conversations';
import ApiClient from '../ApiClient'; import ApiClient from '../ApiClient';
import describeWithAPIMock from './apiSpecHelper';
describe('#ConversationApi', () => { describe('#ConversationApi', () => {
it('creates correct instance', () => { it('creates correct instance', () => {
@@ -14,10 +13,26 @@ describe('#ConversationApi', () => {
expect(conversationsAPI).toHaveProperty('updateLabels'); expect(conversationsAPI).toHaveProperty('updateLabels');
}); });
describeWithAPIMock('API calls', context => { describe('API calls', () => {
const originalAxios = window.axios;
const axiosMock = {
post: jest.fn(() => Promise.resolve()),
get: jest.fn(() => Promise.resolve()),
patch: jest.fn(() => Promise.resolve()),
delete: jest.fn(() => Promise.resolve()),
};
beforeEach(() => {
window.axios = axiosMock;
});
afterEach(() => {
window.axios = originalAxios;
});
it('#getLabels', () => { it('#getLabels', () => {
conversationsAPI.getLabels(1); conversationsAPI.getLabels(1);
expect(context.axiosMock.get).toHaveBeenCalledWith( expect(axiosMock.get).toHaveBeenCalledWith(
'/api/v1/conversations/1/labels' '/api/v1/conversations/1/labels'
); );
}); });
@@ -25,7 +40,7 @@ describe('#ConversationApi', () => {
it('#updateLabels', () => { it('#updateLabels', () => {
const labels = ['support-query']; const labels = ['support-query'];
conversationsAPI.updateLabels(1, labels); conversationsAPI.updateLabels(1, labels);
expect(context.axiosMock.post).toHaveBeenCalledWith( expect(axiosMock.post).toHaveBeenCalledWith(
'/api/v1/conversations/1/labels', '/api/v1/conversations/1/labels',
{ {
labels, labels,

View File

@@ -1,6 +1,5 @@
import csatReportsAPI from '../csatReports'; import csatReportsAPI from '../csatReports';
import ApiClient from '../ApiClient'; import ApiClient from '../ApiClient';
import describeWithAPIMock from './apiSpecHelper';
describe('#Reports API', () => { describe('#Reports API', () => {
it('creates correct instance', () => { it('creates correct instance', () => {
@@ -9,10 +8,26 @@ describe('#Reports API', () => {
expect(csatReportsAPI).toHaveProperty('get'); expect(csatReportsAPI).toHaveProperty('get');
expect(csatReportsAPI).toHaveProperty('getMetrics'); expect(csatReportsAPI).toHaveProperty('getMetrics');
}); });
describeWithAPIMock('API calls', context => { describe('API calls', () => {
const originalAxios = window.axios;
const axiosMock = {
post: jest.fn(() => Promise.resolve()),
get: jest.fn(() => Promise.resolve()),
patch: jest.fn(() => Promise.resolve()),
delete: jest.fn(() => Promise.resolve()),
};
beforeEach(() => {
window.axios = axiosMock;
});
afterEach(() => {
window.axios = originalAxios;
});
it('#get', () => { it('#get', () => {
csatReportsAPI.get({ page: 1, from: 1622485800, to: 1623695400 }); csatReportsAPI.get({ page: 1, from: 1622485800, to: 1623695400 });
expect(context.axiosMock.get).toHaveBeenCalledWith( expect(axiosMock.get).toHaveBeenCalledWith(
'/api/v1/csat_survey_responses', '/api/v1/csat_survey_responses',
{ {
params: { params: {
@@ -26,7 +41,7 @@ describe('#Reports API', () => {
}); });
it('#getMetrics', () => { it('#getMetrics', () => {
csatReportsAPI.getMetrics({ from: 1622485800, to: 1623695400 }); csatReportsAPI.getMetrics({ from: 1622485800, to: 1623695400 });
expect(context.axiosMock.get).toHaveBeenCalledWith( expect(axiosMock.get).toHaveBeenCalledWith(
'/api/v1/csat_survey_responses/metrics', '/api/v1/csat_survey_responses/metrics',
{ {
params: { since: 1622485800, until: 1623695400 }, params: { since: 1622485800, until: 1623695400 },
@@ -39,7 +54,7 @@ describe('#Reports API', () => {
to: 1623695400, to: 1623695400,
user_ids: 1, user_ids: 1,
}); });
expect(context.axiosMock.get).toHaveBeenCalledWith( expect(axiosMock.get).toHaveBeenCalledWith(
'/api/v1/csat_survey_responses/download', '/api/v1/csat_survey_responses/download',
{ {
params: { params: {

View File

@@ -1,6 +1,5 @@
import conversationAPI from '../../inbox/conversation'; import conversationAPI from '../../inbox/conversation';
import ApiClient from '../../ApiClient'; import ApiClient from '../../ApiClient';
import describeWithAPIMock from '../apiSpecHelper';
describe('#ConversationAPI', () => { describe('#ConversationAPI', () => {
it('creates correct instance', () => { it('creates correct instance', () => {
@@ -22,7 +21,23 @@ describe('#ConversationAPI', () => {
expect(conversationAPI).toHaveProperty('filter'); expect(conversationAPI).toHaveProperty('filter');
}); });
describeWithAPIMock('API calls', context => { describe('API calls', () => {
const originalAxios = window.axios;
const axiosMock = {
post: jest.fn(() => Promise.resolve()),
get: jest.fn(() => Promise.resolve()),
patch: jest.fn(() => Promise.resolve()),
delete: jest.fn(() => Promise.resolve()),
};
beforeEach(() => {
window.axios = axiosMock;
});
afterEach(() => {
window.axios = originalAxios;
});
it('#get conversations', () => { it('#get conversations', () => {
conversationAPI.get({ conversationAPI.get({
inboxId: 1, inboxId: 1,
@@ -32,19 +47,16 @@ describe('#ConversationAPI', () => {
labels: [], labels: [],
teamId: 1, teamId: 1,
}); });
expect(context.axiosMock.get).toHaveBeenCalledWith( expect(axiosMock.get).toHaveBeenCalledWith('/api/v1/conversations', {
'/api/v1/conversations', params: {
{ inbox_id: 1,
params: { team_id: 1,
inbox_id: 1, status: 'open',
team_id: 1, assignee_type: 'me',
status: 'open', page: 1,
assignee_type: 'me', labels: [],
page: 1, },
labels: [], });
},
}
);
}); });
it('#search', () => { it('#search', () => {
@@ -53,7 +65,7 @@ describe('#ConversationAPI', () => {
page: 1, page: 1,
}); });
expect(context.axiosMock.get).toHaveBeenCalledWith( expect(axiosMock.get).toHaveBeenCalledWith(
'/api/v1/conversations/search', '/api/v1/conversations/search',
{ {
params: { params: {
@@ -66,7 +78,7 @@ describe('#ConversationAPI', () => {
it('#toggleStatus', () => { it('#toggleStatus', () => {
conversationAPI.toggleStatus({ conversationId: 12, status: 'online' }); conversationAPI.toggleStatus({ conversationId: 12, status: 'online' });
expect(context.axiosMock.post).toHaveBeenCalledWith( expect(axiosMock.post).toHaveBeenCalledWith(
`/api/v1/conversations/12/toggle_status`, `/api/v1/conversations/12/toggle_status`,
{ {
status: 'online', status: 'online',
@@ -77,7 +89,7 @@ describe('#ConversationAPI', () => {
it('#assignAgent', () => { it('#assignAgent', () => {
conversationAPI.assignAgent({ conversationId: 12, agentId: 34 }); conversationAPI.assignAgent({ conversationId: 12, agentId: 34 });
expect(context.axiosMock.post).toHaveBeenCalledWith( expect(axiosMock.post).toHaveBeenCalledWith(
`/api/v1/conversations/12/assignments?assignee_id=34`, `/api/v1/conversations/12/assignments?assignee_id=34`,
{} {}
); );
@@ -85,7 +97,7 @@ describe('#ConversationAPI', () => {
it('#assignTeam', () => { it('#assignTeam', () => {
conversationAPI.assignTeam({ conversationId: 12, teamId: 1 }); conversationAPI.assignTeam({ conversationId: 12, teamId: 1 });
expect(context.axiosMock.post).toHaveBeenCalledWith( expect(axiosMock.post).toHaveBeenCalledWith(
`/api/v1/conversations/12/assignments`, `/api/v1/conversations/12/assignments`,
{ {
team_id: 1, team_id: 1,
@@ -95,7 +107,7 @@ describe('#ConversationAPI', () => {
it('#markMessageRead', () => { it('#markMessageRead', () => {
conversationAPI.markMessageRead({ id: 12 }); conversationAPI.markMessageRead({ id: 12 });
expect(context.axiosMock.post).toHaveBeenCalledWith( expect(axiosMock.post).toHaveBeenCalledWith(
`/api/v1/conversations/12/update_last_seen` `/api/v1/conversations/12/update_last_seen`
); );
}); });
@@ -105,7 +117,7 @@ describe('#ConversationAPI', () => {
conversationId: 12, conversationId: 12,
status: 'typing_on', status: 'typing_on',
}); });
expect(context.axiosMock.post).toHaveBeenCalledWith( expect(axiosMock.post).toHaveBeenCalledWith(
`/api/v1/conversations/12/toggle_typing_status`, `/api/v1/conversations/12/toggle_typing_status`,
{ {
typing_status: 'typing_on', typing_status: 'typing_on',
@@ -115,14 +127,14 @@ describe('#ConversationAPI', () => {
it('#mute', () => { it('#mute', () => {
conversationAPI.mute(45); conversationAPI.mute(45);
expect(context.axiosMock.post).toHaveBeenCalledWith( expect(axiosMock.post).toHaveBeenCalledWith(
'/api/v1/conversations/45/mute' '/api/v1/conversations/45/mute'
); );
}); });
it('#unmute', () => { it('#unmute', () => {
conversationAPI.unmute(45); conversationAPI.unmute(45);
expect(context.axiosMock.post).toHaveBeenCalledWith( expect(axiosMock.post).toHaveBeenCalledWith(
'/api/v1/conversations/45/unmute' '/api/v1/conversations/45/unmute'
); );
}); });
@@ -135,18 +147,15 @@ describe('#ConversationAPI', () => {
labels: [], labels: [],
teamId: 1, teamId: 1,
}); });
expect(context.axiosMock.get).toHaveBeenCalledWith( expect(axiosMock.get).toHaveBeenCalledWith('/api/v1/conversations/meta', {
'/api/v1/conversations/meta', params: {
{ inbox_id: 1,
params: { team_id: 1,
inbox_id: 1, status: 'open',
team_id: 1, assignee_type: 'me',
status: 'open', labels: [],
assignee_type: 'me', },
labels: [], });
},
}
);
}); });
it('#sendEmailTranscript', () => { it('#sendEmailTranscript', () => {
@@ -154,7 +163,7 @@ describe('#ConversationAPI', () => {
conversationId: 45, conversationId: 45,
email: 'john@acme.inc', email: 'john@acme.inc',
}); });
expect(context.axiosMock.post).toHaveBeenCalledWith( expect(axiosMock.post).toHaveBeenCalledWith(
'/api/v1/conversations/45/transcript', '/api/v1/conversations/45/transcript',
{ {
email: 'john@acme.inc', email: 'john@acme.inc',
@@ -167,7 +176,7 @@ describe('#ConversationAPI', () => {
conversationId: 45, conversationId: 45,
customAttributes: { order_d: '1001' }, customAttributes: { order_d: '1001' },
}); });
expect(context.axiosMock.post).toHaveBeenCalledWith( expect(axiosMock.post).toHaveBeenCalledWith(
'/api/v1/conversations/45/custom_attributes', '/api/v1/conversations/45/custom_attributes',
{ {
custom_attributes: { order_d: '1001' }, custom_attributes: { order_d: '1001' },
@@ -202,9 +211,7 @@ describe('#ConversationAPI', () => {
}, },
}; };
conversationAPI.filter(payload); conversationAPI.filter(payload);
expect( expect(axiosMock.post).toHaveBeenCalledWith(
context.axiosMock.post
).toHaveBeenCalledWith(
'/api/v1/conversations/filter', '/api/v1/conversations/filter',
payload.queryData, payload.queryData,
{ params: { page: payload.page } } { params: { page: payload.page } }
@@ -213,7 +220,7 @@ describe('#ConversationAPI', () => {
it('#getAllAttachments', () => { it('#getAllAttachments', () => {
conversationAPI.getAllAttachments(1); conversationAPI.getAllAttachments(1);
expect(context.axiosMock.get).toHaveBeenCalledWith( expect(axiosMock.get).toHaveBeenCalledWith(
'/api/v1/conversations/1/attachments' '/api/v1/conversations/1/attachments'
); );
}); });

View File

@@ -1,6 +1,5 @@
import messageAPI, { buildCreatePayload } from '../../inbox/message'; import messageAPI, { buildCreatePayload } from '../../inbox/message';
import ApiClient from '../../ApiClient'; import ApiClient from '../../ApiClient';
import describeWithAPIMock from '../apiSpecHelper';
describe('#ConversationAPI', () => { describe('#ConversationAPI', () => {
it('creates correct instance', () => { it('creates correct instance', () => {
@@ -13,13 +12,29 @@ describe('#ConversationAPI', () => {
expect(messageAPI).toHaveProperty('getPreviousMessages'); expect(messageAPI).toHaveProperty('getPreviousMessages');
}); });
describeWithAPIMock('API calls', context => { describe('API calls', () => {
const originalAxios = window.axios;
const axiosMock = {
post: jest.fn(() => Promise.resolve()),
get: jest.fn(() => Promise.resolve()),
patch: jest.fn(() => Promise.resolve()),
delete: jest.fn(() => Promise.resolve()),
};
beforeEach(() => {
window.axios = axiosMock;
});
afterEach(() => {
window.axios = originalAxios;
});
it('#getPreviousMessages', () => { it('#getPreviousMessages', () => {
messageAPI.getPreviousMessages({ messageAPI.getPreviousMessages({
conversationId: 12, conversationId: 12,
before: 4573, before: 4573,
}); });
expect(context.axiosMock.get).toHaveBeenCalledWith( expect(axiosMock.get).toHaveBeenCalledWith(
`/api/v1/conversations/12/messages`, `/api/v1/conversations/12/messages`,
{ {
params: { params: {
@@ -35,7 +50,6 @@ describe('#ConversationAPI', () => {
message: 'test content', message: 'test content',
echoId: 12, echoId: 12,
isPrivate: true, isPrivate: true,
files: [new Blob(['test-content'], { type: 'application/pdf' })], files: [new Blob(['test-content'], { type: 'application/pdf' })],
}); });
expect(formPayload).toBeInstanceOf(FormData); expect(formPayload).toBeInstanceOf(FormData);
@@ -58,8 +72,10 @@ describe('#ConversationAPI', () => {
private: false, private: false,
echo_id: 12, echo_id: 12,
content_attributes: { in_reply_to: 12 }, content_attributes: { in_reply_to: 12 },
bcc_emails: '',
cc_emails: '', cc_emails: '',
bcc_emails: '',
to_emails: '',
template_params: undefined,
}); });
}); });
}); });

View File

@@ -1,6 +1,5 @@
import inboxesAPI from '../inboxes'; import inboxesAPI from '../inboxes';
import ApiClient from '../ApiClient'; import ApiClient from '../ApiClient';
import describeWithAPIMock from './apiSpecHelper';
describe('#InboxesAPI', () => { describe('#InboxesAPI', () => {
it('creates correct instance', () => { it('creates correct instance', () => {
@@ -14,19 +13,32 @@ describe('#InboxesAPI', () => {
expect(inboxesAPI).toHaveProperty('getAgentBot'); expect(inboxesAPI).toHaveProperty('getAgentBot');
expect(inboxesAPI).toHaveProperty('setAgentBot'); expect(inboxesAPI).toHaveProperty('setAgentBot');
}); });
describeWithAPIMock('API calls', context => {
describe('API calls', () => {
const originalAxios = window.axios;
const axiosMock = {
post: jest.fn(() => Promise.resolve()),
get: jest.fn(() => Promise.resolve()),
patch: jest.fn(() => Promise.resolve()),
delete: jest.fn(() => Promise.resolve()),
};
beforeEach(() => {
window.axios = axiosMock;
});
afterEach(() => {
window.axios = originalAxios;
});
it('#getCampaigns', () => { it('#getCampaigns', () => {
inboxesAPI.getCampaigns(2); inboxesAPI.getCampaigns(2);
expect(context.axiosMock.get).toHaveBeenCalledWith( expect(axiosMock.get).toHaveBeenCalledWith('/api/v1/inboxes/2/campaigns');
'/api/v1/inboxes/2/campaigns'
);
}); });
it('#deleteInboxAvatar', () => { it('#deleteInboxAvatar', () => {
inboxesAPI.deleteInboxAvatar(2); inboxesAPI.deleteInboxAvatar(2);
expect(context.axiosMock.delete).toHaveBeenCalledWith( expect(axiosMock.delete).toHaveBeenCalledWith('/api/v1/inboxes/2/avatar');
'/api/v1/inboxes/2/avatar'
);
}); });
}); });
}); });

View File

@@ -1,6 +1,5 @@
import integrationAPI from '../integrations'; import integrationAPI from '../integrations';
import ApiClient from '../ApiClient'; import ApiClient from '../ApiClient';
import describeWithAPIMock from './apiSpecHelper';
describe('#integrationAPI', () => { describe('#integrationAPI', () => {
it('creates correct instance', () => { it('creates correct instance', () => {
@@ -16,11 +15,27 @@ describe('#integrationAPI', () => {
expect(integrationAPI).toHaveProperty('listAllSlackChannels'); expect(integrationAPI).toHaveProperty('listAllSlackChannels');
expect(integrationAPI).toHaveProperty('deleteHook'); expect(integrationAPI).toHaveProperty('deleteHook');
}); });
describeWithAPIMock('API calls', context => { describe('API calls', () => {
const originalAxios = window.axios;
const axiosMock = {
post: jest.fn(() => Promise.resolve()),
get: jest.fn(() => Promise.resolve()),
patch: jest.fn(() => Promise.resolve()),
delete: jest.fn(() => Promise.resolve()),
};
beforeEach(() => {
window.axios = axiosMock;
});
afterEach(() => {
window.axios = originalAxios;
});
it('#connectSlack', () => { it('#connectSlack', () => {
const code = 'SDNFJNSDFNDSJN'; const code = 'SDNFJNSDFNDSJN';
integrationAPI.connectSlack(code); integrationAPI.connectSlack(code);
expect(context.axiosMock.post).toHaveBeenCalledWith( expect(axiosMock.post).toHaveBeenCalledWith(
'/api/v1/integrations/slack', '/api/v1/integrations/slack',
{ {
code, code,
@@ -31,7 +46,7 @@ describe('#integrationAPI', () => {
it('#updateSlack', () => { it('#updateSlack', () => {
const updateObj = { referenceId: 'SDFSDGSVE' }; const updateObj = { referenceId: 'SDFSDGSVE' };
integrationAPI.updateSlack(updateObj); integrationAPI.updateSlack(updateObj);
expect(context.axiosMock.patch).toHaveBeenCalledWith( expect(axiosMock.patch).toHaveBeenCalledWith(
'/api/v1/integrations/slack', '/api/v1/integrations/slack',
{ {
reference_id: updateObj.referenceId, reference_id: updateObj.referenceId,
@@ -41,16 +56,14 @@ describe('#integrationAPI', () => {
it('#listAllSlackChannels', () => { it('#listAllSlackChannels', () => {
integrationAPI.listAllSlackChannels(); integrationAPI.listAllSlackChannels();
expect(context.axiosMock.get).toHaveBeenCalledWith( expect(axiosMock.get).toHaveBeenCalledWith(
'/api/v1/integrations/slack/list_all_channels' '/api/v1/integrations/slack/list_all_channels'
); );
}); });
it('#delete', () => { it('#delete', () => {
integrationAPI.delete(2); integrationAPI.delete(2);
expect(context.axiosMock.delete).toHaveBeenCalledWith( expect(axiosMock.delete).toHaveBeenCalledWith('/api/v1/integrations/2');
'/api/v1/integrations/2'
);
}); });
it('#createHook', () => { it('#createHook', () => {
@@ -59,7 +72,7 @@ describe('#integrationAPI', () => {
settings: { api_key: 'SDFSDGSVE' }, settings: { api_key: 'SDFSDGSVE' },
}; };
integrationAPI.createHook(hookData); integrationAPI.createHook(hookData);
expect(context.axiosMock.post).toHaveBeenCalledWith( expect(axiosMock.post).toHaveBeenCalledWith(
'/api/v1/integrations/hooks', '/api/v1/integrations/hooks',
hookData hookData
); );
@@ -67,7 +80,7 @@ describe('#integrationAPI', () => {
it('#deleteHook', () => { it('#deleteHook', () => {
integrationAPI.deleteHook(2); integrationAPI.deleteHook(2);
expect(context.axiosMock.delete).toHaveBeenCalledWith( expect(axiosMock.delete).toHaveBeenCalledWith(
'/api/v1/integrations/hooks/2' '/api/v1/integrations/hooks/2'
); );
}); });

View File

@@ -1,6 +1,5 @@
import DyteAPIClient from '../../integrations/dyte'; import DyteAPIClient from '../../integrations/dyte';
import ApiClient from '../../ApiClient'; import ApiClient from '../../ApiClient';
import describeWithAPIMock from '../apiSpecHelper';
describe('#accountAPI', () => { describe('#accountAPI', () => {
it('creates correct instance', () => { it('creates correct instance', () => {
@@ -9,10 +8,26 @@ describe('#accountAPI', () => {
expect(DyteAPIClient).toHaveProperty('addParticipantToMeeting'); expect(DyteAPIClient).toHaveProperty('addParticipantToMeeting');
}); });
describeWithAPIMock('createAMeeting', context => { describe('createAMeeting', () => {
const originalAxios = window.axios;
const axiosMock = {
post: jest.fn(() => Promise.resolve()),
get: jest.fn(() => Promise.resolve()),
patch: jest.fn(() => Promise.resolve()),
delete: jest.fn(() => Promise.resolve()),
};
beforeEach(() => {
window.axios = axiosMock;
});
afterEach(() => {
window.axios = originalAxios;
});
it('creates a valid request', () => { it('creates a valid request', () => {
DyteAPIClient.createAMeeting(1); DyteAPIClient.createAMeeting(1);
expect(context.axiosMock.post).toHaveBeenCalledWith( expect(axiosMock.post).toHaveBeenCalledWith(
'/api/v1/integrations/dyte/create_a_meeting', '/api/v1/integrations/dyte/create_a_meeting',
{ {
conversation_id: 1, conversation_id: 1,
@@ -21,10 +36,26 @@ describe('#accountAPI', () => {
}); });
}); });
describeWithAPIMock('addParticipantToMeeting', context => { describe('addParticipantToMeeting', () => {
const originalAxios = window.axios;
const axiosMock = {
post: jest.fn(() => Promise.resolve()),
get: jest.fn(() => Promise.resolve()),
patch: jest.fn(() => Promise.resolve()),
delete: jest.fn(() => Promise.resolve()),
};
beforeEach(() => {
window.axios = axiosMock;
});
afterEach(() => {
window.axios = originalAxios;
});
it('creates a valid request', () => { it('creates a valid request', () => {
DyteAPIClient.addParticipantToMeeting(1); DyteAPIClient.addParticipantToMeeting(1);
expect(context.axiosMock.post).toHaveBeenCalledWith( expect(axiosMock.post).toHaveBeenCalledWith(
'/api/v1/integrations/dyte/add_participant_to_meeting', '/api/v1/integrations/dyte/add_participant_to_meeting',
{ {
message_id: 1, message_id: 1,

View File

@@ -1,6 +1,5 @@
import notificationsAPI from '../notifications'; import notificationsAPI from '../notifications';
import ApiClient from '../ApiClient'; import ApiClient from '../ApiClient';
import describeWithAPIMock from './apiSpecHelper';
describe('#NotificationAPI', () => { describe('#NotificationAPI', () => {
it('creates correct instance', () => { it('creates correct instance', () => {
@@ -11,31 +10,47 @@ describe('#NotificationAPI', () => {
expect(notificationsAPI).toHaveProperty('read'); expect(notificationsAPI).toHaveProperty('read');
expect(notificationsAPI).toHaveProperty('readAll'); expect(notificationsAPI).toHaveProperty('readAll');
}); });
describeWithAPIMock('API calls', context => { describe('API calls', () => {
const originalAxios = window.axios;
const axiosMock = {
post: jest.fn(() => Promise.resolve()),
get: jest.fn(() => Promise.resolve()),
patch: jest.fn(() => Promise.resolve()),
delete: jest.fn(() => Promise.resolve()),
};
beforeEach(() => {
window.axios = axiosMock;
});
afterEach(() => {
window.axios = originalAxios;
});
it('#get', () => { it('#get', () => {
notificationsAPI.get(1); notificationsAPI.get(1);
expect(context.axiosMock.get).toHaveBeenCalledWith( expect(axiosMock.get).toHaveBeenCalledWith(
'/api/v1/notifications?page=1' '/api/v1/notifications?page=1'
); );
}); });
it('#getNotifications', () => { it('#getNotifications', () => {
notificationsAPI.getNotifications(1); notificationsAPI.getNotifications(1);
expect(context.axiosMock.get).toHaveBeenCalledWith( expect(axiosMock.get).toHaveBeenCalledWith(
'/api/v1/notifications/1/notifications' '/api/v1/notifications/1/notifications'
); );
}); });
it('#getUnreadCount', () => { it('#getUnreadCount', () => {
notificationsAPI.getUnreadCount(); notificationsAPI.getUnreadCount();
expect(context.axiosMock.get).toHaveBeenCalledWith( expect(axiosMock.get).toHaveBeenCalledWith(
'/api/v1/notifications/unread_count' '/api/v1/notifications/unread_count'
); );
}); });
it('#read', () => { it('#read', () => {
notificationsAPI.read(48670, 'Conversation'); notificationsAPI.read(48670, 'Conversation');
expect(context.axiosMock.post).toHaveBeenCalledWith( expect(axiosMock.post).toHaveBeenCalledWith(
'/api/v1/notifications/read_all', '/api/v1/notifications/read_all',
{ {
primary_actor_id: 'Conversation', primary_actor_id: 'Conversation',
@@ -46,7 +61,7 @@ describe('#NotificationAPI', () => {
it('#readAll', () => { it('#readAll', () => {
notificationsAPI.readAll(); notificationsAPI.readAll();
expect(context.axiosMock.post).toHaveBeenCalledWith( expect(axiosMock.post).toHaveBeenCalledWith(
'/api/v1/notifications/read_all' '/api/v1/notifications/read_all'
); );
}); });

View File

@@ -1,6 +1,5 @@
import reportsAPI from '../reports'; import reportsAPI from '../reports';
import ApiClient from '../ApiClient'; import ApiClient from '../ApiClient';
import describeWithAPIMock from './apiSpecHelper';
describe('#Reports API', () => { describe('#Reports API', () => {
it('creates correct instance', () => { it('creates correct instance', () => {
@@ -18,14 +17,30 @@ describe('#Reports API', () => {
expect(reportsAPI).toHaveProperty('getInboxReports'); expect(reportsAPI).toHaveProperty('getInboxReports');
expect(reportsAPI).toHaveProperty('getTeamReports'); expect(reportsAPI).toHaveProperty('getTeamReports');
}); });
describeWithAPIMock('API calls', context => { describe('API calls', () => {
const originalAxios = window.axios;
const axiosMock = {
post: jest.fn(() => Promise.resolve()),
get: jest.fn(() => Promise.resolve()),
patch: jest.fn(() => Promise.resolve()),
delete: jest.fn(() => Promise.resolve()),
};
beforeEach(() => {
window.axios = axiosMock;
});
afterEach(() => {
window.axios = originalAxios;
});
it('#getAccountReports', () => { it('#getAccountReports', () => {
reportsAPI.getReports({ reportsAPI.getReports({
metric: 'conversations_count', metric: 'conversations_count',
from: 1621103400, from: 1621103400,
to: 1621621800, to: 1621621800,
}); });
expect(context.axiosMock.get).toHaveBeenCalledWith('/api/v2/reports', { expect(axiosMock.get).toHaveBeenCalledWith('/api/v2/reports', {
params: { params: {
metric: 'conversations_count', metric: 'conversations_count',
since: 1621103400, since: 1621103400,
@@ -38,20 +53,17 @@ describe('#Reports API', () => {
it('#getAccountSummary', () => { it('#getAccountSummary', () => {
reportsAPI.getSummary(1621103400, 1621621800); reportsAPI.getSummary(1621103400, 1621621800);
expect(context.axiosMock.get).toHaveBeenCalledWith( expect(axiosMock.get).toHaveBeenCalledWith('/api/v2/reports/summary', {
'/api/v2/reports/summary', params: {
{ business_hours: undefined,
params: { group_by: undefined,
business_hours: undefined, id: undefined,
group_by: undefined, since: 1621103400,
id: undefined, timezone_offset: -0,
since: 1621103400, type: 'account',
timezone_offset: -0, until: 1621621800,
type: 'account', },
until: 1621621800, });
},
}
);
}); });
it('#getAgentReports', () => { it('#getAgentReports', () => {
@@ -60,60 +72,48 @@ describe('#Reports API', () => {
to: 1621621800, to: 1621621800,
businessHours: true, businessHours: true,
}); });
expect(context.axiosMock.get).toHaveBeenCalledWith( expect(axiosMock.get).toHaveBeenCalledWith('/api/v2/reports/agents', {
'/api/v2/reports/agents', params: {
{ since: 1621103400,
params: { until: 1621621800,
since: 1621103400, business_hours: true,
until: 1621621800, },
business_hours: true, });
},
}
);
}); });
it('#getLabelReports', () => { it('#getLabelReports', () => {
reportsAPI.getLabelReports({ from: 1621103400, to: 1621621800 }); reportsAPI.getLabelReports({ from: 1621103400, to: 1621621800 });
expect(context.axiosMock.get).toHaveBeenCalledWith( expect(axiosMock.get).toHaveBeenCalledWith('/api/v2/reports/labels', {
'/api/v2/reports/labels', params: {
{ since: 1621103400,
params: { until: 1621621800,
since: 1621103400, },
until: 1621621800, });
},
}
);
}); });
it('#getInboxReports', () => { it('#getInboxReports', () => {
reportsAPI.getInboxReports({ from: 1621103400, to: 1621621800 }); reportsAPI.getInboxReports({ from: 1621103400, to: 1621621800 });
expect(context.axiosMock.get).toHaveBeenCalledWith( expect(axiosMock.get).toHaveBeenCalledWith('/api/v2/reports/inboxes', {
'/api/v2/reports/inboxes', params: {
{ since: 1621103400,
params: { until: 1621621800,
since: 1621103400, },
until: 1621621800, });
},
}
);
}); });
it('#getTeamReports', () => { it('#getTeamReports', () => {
reportsAPI.getTeamReports({ from: 1621103400, to: 1621621800 }); reportsAPI.getTeamReports({ from: 1621103400, to: 1621621800 });
expect(context.axiosMock.get).toHaveBeenCalledWith( expect(axiosMock.get).toHaveBeenCalledWith('/api/v2/reports/teams', {
'/api/v2/reports/teams', params: {
{ since: 1621103400,
params: { until: 1621621800,
since: 1621103400, },
until: 1621621800, });
},
}
);
}); });
it('#getConversationMetric', () => { it('#getConversationMetric', () => {
reportsAPI.getConversationMetric('account'); reportsAPI.getConversationMetric('account');
expect(context.axiosMock.get).toHaveBeenCalledWith( expect(axiosMock.get).toHaveBeenCalledWith(
'/api/v2/reports/conversations', '/api/v2/reports/conversations',
{ {
params: { params: {

View File

@@ -1,6 +1,5 @@
import teamsAPI from '../teams'; import teamsAPI from '../teams';
import ApiClient from '../ApiClient'; import ApiClient from '../ApiClient';
import describeWithAPIMock from './apiSpecHelper';
describe('#TeamsAPI', () => { describe('#TeamsAPI', () => {
it('creates correct instance', () => { it('creates correct instance', () => {
@@ -14,17 +13,33 @@ describe('#TeamsAPI', () => {
expect(teamsAPI).toHaveProperty('addAgents'); expect(teamsAPI).toHaveProperty('addAgents');
expect(teamsAPI).toHaveProperty('updateAgents'); expect(teamsAPI).toHaveProperty('updateAgents');
}); });
describeWithAPIMock('API calls', context => { describe('API calls', () => {
const originalAxios = window.axios;
const axiosMock = {
post: jest.fn(() => Promise.resolve()),
get: jest.fn(() => Promise.resolve()),
patch: jest.fn(() => Promise.resolve()),
delete: jest.fn(() => Promise.resolve()),
};
beforeEach(() => {
window.axios = axiosMock;
});
afterEach(() => {
window.axios = originalAxios;
});
it('#getAgents', () => { it('#getAgents', () => {
teamsAPI.getAgents({ teamId: 1 }); teamsAPI.getAgents({ teamId: 1 });
expect(context.axiosMock.get).toHaveBeenCalledWith( expect(axiosMock.get).toHaveBeenCalledWith(
'/api/v1/teams/1/team_members' '/api/v1/teams/1/team_members'
); );
}); });
it('#addAgents', () => { it('#addAgents', () => {
teamsAPI.addAgents({ teamId: 1, agentsList: { user_ids: [1, 10, 21] } }); teamsAPI.addAgents({ teamId: 1, agentsList: { user_ids: [1, 10, 21] } });
expect(context.axiosMock.post).toHaveBeenCalledWith( expect(axiosMock.post).toHaveBeenCalledWith(
'/api/v1/teams/1/team_members', '/api/v1/teams/1/team_members',
{ {
user_ids: { user_ids: [1, 10, 21] }, user_ids: { user_ids: [1, 10, 21] },
@@ -38,7 +53,7 @@ describe('#TeamsAPI', () => {
teamId: 1, teamId: 1,
agentsList, agentsList,
}); });
expect(context.axiosMock.patch).toHaveBeenCalledWith( expect(axiosMock.patch).toHaveBeenCalledWith(
'/api/v1/teams/1/team_members', '/api/v1/teams/1/team_members',
{ {
user_ids: agentsList, user_ids: agentsList,

View File

@@ -10,7 +10,8 @@
<div <div
class="flex items-center justify-between py-0 px-4" class="flex items-center justify-between py-0 px-4"
:class="{ :class="{
'pb-3 border-b border-slate-75 dark:border-slate-700': hasAppliedFiltersOrActiveFolders, 'pb-3 border-b border-slate-75 dark:border-slate-700':
hasAppliedFiltersOrActiveFolders,
}" }"
> >
<div class="flex max-w-[85%] justify-center items-center"> <div class="flex max-w-[85%] justify-center items-center">
@@ -24,9 +25,7 @@
v-if="!hasAppliedFiltersOrActiveFolders" v-if="!hasAppliedFiltersOrActiveFolders"
class="p-1 my-0.5 mx-1 rounded-md capitalize bg-slate-50 dark:bg-slate-800 text-xxs text-slate-600 dark:text-slate-300" class="p-1 my-0.5 mx-1 rounded-md capitalize bg-slate-50 dark:bg-slate-800 text-xxs text-slate-600 dark:text-slate-300"
> >
{{ {{ $t(`CHAT_LIST.CHAT_STATUS_FILTER_ITEMS.${activeStatus}.TEXT`) }}
this.$t(`CHAT_LIST.CHAT_STATUS_FILTER_ITEMS.${activeStatus}.TEXT`)
}}
</span> </span>
</div> </div>
<div class="flex items-center gap-1"> <div class="flex items-center gap-1">
@@ -642,10 +641,8 @@ export default {
}, },
handleKeyEvents(e) { handleKeyEvents(e) {
if (hasPressedAltAndJKey(e)) { if (hasPressedAltAndJKey(e)) {
const { const { allConversations, activeConversationIndex } =
allConversations, this.getKeyboardListenerParams();
activeConversationIndex,
} = this.getKeyboardListenerParams();
if (activeConversationIndex === -1) { if (activeConversationIndex === -1) {
allConversations[0].click(); allConversations[0].click();
} }

View File

@@ -13,10 +13,10 @@
/> />
<div class="flex flex-row justify-end gap-2 py-2 px-0 w-full"> <div class="flex flex-row justify-end gap-2 py-2 px-0 w-full">
<woot-button variant="clear" @click.prevent="onClose"> <woot-button variant="clear" @click.prevent="onClose">
{{ this.$t('CONVERSATION.CUSTOM_SNOOZE.CANCEL') }} {{ $t('CONVERSATION.CUSTOM_SNOOZE.CANCEL') }}
</woot-button> </woot-button>
<woot-button> <woot-button>
{{ this.$t('CONVERSATION.CUSTOM_SNOOZE.APPLY') }} {{ $t('CONVERSATION.CUSTOM_SNOOZE.APPLY') }}
</woot-button> </woot-button>
</div> </div>
</form> </form>

View File

@@ -1,6 +1,6 @@
<template> <template>
<div class="text--container"> <div class="text--container">
<woot-button size="small" class=" button--text" @click="onCopy"> <woot-button size="small" class="button--text" @click="onCopy">
{{ $t('COMPONENTS.CODE.BUTTON_TEXT') }} {{ $t('COMPONENTS.CODE.BUTTON_TEXT') }}
</woot-button> </woot-button>
<woot-button <woot-button

View File

@@ -66,9 +66,9 @@ export default {
'right-aligned': 'right-aligned', 'right-aligned': 'right-aligned',
}; };
return `modal-mask skip-context-menu ${modalClassNameMap[ return `modal-mask skip-context-menu ${
this.modalType modalClassNameMap[this.modalType] || ''
] || ''}`; }`;
}, },
}, },
mounted() { mounted() {

View File

@@ -2,7 +2,8 @@
<div <div
class="ml-0 mr-0 flex pt-0 pr-4 pb-4 pl-0" class="ml-0 mr-0 flex pt-0 pr-4 pb-4 pl-0"
:class="{ :class="{
'pt-4 border-b border-solid border-slate-50 dark:border-slate-700/30': showBorder, 'pt-4 border-b border-solid border-slate-50 dark:border-slate-700/30':
showBorder,
}" }"
> >
<div class="w-[30%] min-w-0 max-w-[30%] pr-12"> <div class="w-[30%] min-w-0 max-w-[30%] pr-12">

View File

@@ -72,10 +72,8 @@ export default {
const { custom_attributes: subscription } = account; const { custom_attributes: subscription } = account;
if (!subscription) return EMPTY_SUBSCRIPTION_INFO; if (!subscription) return EMPTY_SUBSCRIPTION_INFO;
const { const { subscription_status: status, subscription_ends_on: endsOn } =
subscription_status: status, subscription;
subscription_ends_on: endsOn,
} = subscription;
return { status, endsOn: new Date(endsOn) }; return { status, endsOn: new Date(endsOn) };
}, },

View File

@@ -1,4 +1,4 @@
const semver = require('semver'); import semver from 'semver';
export const hasAnUpdateAvailable = (latestVersion, currentVersion) => { export const hasAnUpdateAvailable = (latestVersion, currentVersion) => {
if (!semver.valid(latestVersion)) { if (!semver.valid(latestVersion)) {

View File

@@ -10,7 +10,7 @@
:is-loading="isLoading" :is-loading="isLoading"
@click="onCmdResolveConversation" @click="onCmdResolveConversation"
> >
{{ this.$t('CONVERSATION.HEADER.RESOLVE_ACTION') }} {{ $t('CONVERSATION.HEADER.RESOLVE_ACTION') }}
</woot-button> </woot-button>
<woot-button <woot-button
v-else-if="isResolved" v-else-if="isResolved"
@@ -21,7 +21,7 @@
:is-loading="isLoading" :is-loading="isLoading"
@click="onCmdOpenConversation" @click="onCmdOpenConversation"
> >
{{ this.$t('CONVERSATION.HEADER.REOPEN_ACTION') }} {{ $t('CONVERSATION.HEADER.REOPEN_ACTION') }}
</woot-button> </woot-button>
<woot-button <woot-button
v-else-if="showOpenButton" v-else-if="showOpenButton"
@@ -31,7 +31,7 @@
:is-loading="isLoading" :is-loading="isLoading"
@click="onCmdOpenConversation" @click="onCmdOpenConversation"
> >
{{ this.$t('CONVERSATION.HEADER.OPEN_ACTION') }} {{ $t('CONVERSATION.HEADER.OPEN_ACTION') }}
</woot-button> </woot-button>
<woot-button <woot-button
v-if="showAdditionalActions" v-if="showAdditionalActions"
@@ -57,7 +57,7 @@
icon="snooze" icon="snooze"
@click="() => openSnoozeModal()" @click="() => openSnoozeModal()"
> >
{{ this.$t('CONVERSATION.RESOLVE_DROPDOWN.SNOOZE_UNTIL') }} {{ $t('CONVERSATION.RESOLVE_DROPDOWN.SNOOZE_UNTIL') }}
</woot-button> </woot-button>
</woot-dropdown-item> </woot-dropdown-item>
<woot-dropdown-item v-if="!isPending"> <woot-dropdown-item v-if="!isPending">
@@ -68,7 +68,7 @@
icon="book-clock" icon="book-clock"
@click="() => toggleStatus(STATUS_TYPE.PENDING)" @click="() => toggleStatus(STATUS_TYPE.PENDING)"
> >
{{ this.$t('CONVERSATION.RESOLVE_DROPDOWN.MARK_PENDING') }} {{ $t('CONVERSATION.RESOLVE_DROPDOWN.MARK_PENDING') }}
</woot-button> </woot-button>
</woot-dropdown-item> </woot-dropdown-item>
</woot-dropdown-menu> </woot-dropdown-menu>

View File

@@ -34,8 +34,8 @@
<woot-submit-button <woot-submit-button
:disabled=" :disabled="
$v.accountName.$invalid || $v.accountName.$invalid ||
$v.accountName.$invalid || $v.accountName.$invalid ||
uiFlags.isCreating uiFlags.isCreating
" "
:button-text="$t('CREATE_ACCOUNT.FORM.SUBMIT')" :button-text="$t('CREATE_ACCOUNT.FORM.SUBMIT')"
:loading="uiFlags.isCreating" :loading="uiFlags.isCreating"

View File

@@ -3,7 +3,8 @@
<button <button
class="text-slate-600 dark:text-slate-100 w-10 h-10 my-2 flex items-center justify-center rounded-lg hover:bg-slate-25 dark:hover:bg-slate-700 dark:hover:text-slate-100 hover:text-slate-600 relative" class="text-slate-600 dark:text-slate-100 w-10 h-10 my-2 flex items-center justify-center rounded-lg hover:bg-slate-25 dark:hover:bg-slate-700 dark:hover:text-slate-100 hover:text-slate-600 relative"
:class="{ :class="{
'bg-woot-50 dark:bg-slate-800 text-woot-500 hover:bg-woot-50': isNotificationPanelActive, 'bg-woot-50 dark:bg-slate-800 text-woot-500 hover:bg-woot-50':
isNotificationPanelActive,
}" }"
@click="openNotificationPanel" @click="openNotificationPanel"
> >

View File

@@ -9,7 +9,8 @@
class="font-medium h-7 my-1 hover:bg-slate-25 hover:text-bg-50 flex items-center px-2 rounded-md dark:hover:bg-slate-800" class="font-medium h-7 my-1 hover:bg-slate-25 hover:text-bg-50 flex items-center px-2 rounded-md dark:hover:bg-slate-800"
:class="{ :class="{
'bg-woot-25 dark:bg-slate-800': isActive, 'bg-woot-25 dark:bg-slate-800': isActive,
'text-ellipsis overflow-hidden whitespace-nowrap max-w-full': shouldTruncate, 'text-ellipsis overflow-hidden whitespace-nowrap max-w-full':
shouldTruncate,
}" }"
@click="navigate" @click="navigate"
> >
@@ -44,7 +45,8 @@
class="text-sm text-slate-700 dark:text-slate-100" class="text-sm text-slate-700 dark:text-slate-100"
:class="{ :class="{
'text-woot-500 dark:text-woot-500': isActive, 'text-woot-500 dark:text-woot-500': isActive,
'text-ellipsis overflow-hidden whitespace-nowrap max-w-full': shouldTruncate, 'text-ellipsis overflow-hidden whitespace-nowrap max-w-full':
shouldTruncate,
}" }"
> >
{{ label }} {{ label }}

View File

@@ -35,7 +35,8 @@
:class="{ :class="{
'text-slate-300 dark:text-slate-600': isCountZero && !isActiveView, 'text-slate-300 dark:text-slate-600': isCountZero && !isActiveView,
'text-slate-600 dark:text-slate-50': !isCountZero && !isActiveView, 'text-slate-600 dark:text-slate-50': !isCountZero && !isActiveView,
'bg-woot-75 dark:bg-woot-200 text-woot-600 dark:text-woot-600': isActiveView, 'bg-woot-75 dark:bg-woot-200 text-woot-600 dark:text-woot-600':
isActiveView,
'bg-slate-50 dark:bg-slate-700': !isActiveView, 'bg-slate-50 dark:bg-slate-700': !isActiveView,
}" }"
> >

View File

@@ -1,6 +1,6 @@
<template> <template>
<div class="animation-container margin-top-1"> <div class="animation-container margin-top-1">
<div class="ai-typing--wrap "> <div class="ai-typing--wrap">
<fluent-icon icon="wand" size="14" class="ai-typing--icon" /> <fluent-icon icon="wand" size="14" class="ai-typing--icon" />
<label> <label>
{{ $t('INTEGRATION_SETTINGS.OPEN_AI.ASSISTANCE_MODAL.AI_WRITING') }} {{ $t('INTEGRATION_SETTINGS.OPEN_AI.ASSISTANCE_MODAL.AI_WRITING') }}

View File

@@ -1,3 +1,4 @@
<!-- eslint-disable vue/no-mutating-props -->
<template> <template>
<div> <div>
<div <div
@@ -255,7 +256,9 @@ export default {
value === 'conversation_attribute' || value === 'conversation_attribute' ||
value === 'contact_attribute' value === 'contact_attribute'
) { ) {
// eslint-disable-next-line vue/no-mutating-props
this.value.custom_attribute_type = this.customAttributeType; this.value.custom_attribute_type = this.customAttributeType;
// eslint-disable-next-line vue/no-mutating-props
} else this.value.custom_attribute_type = ''; } else this.value.custom_attribute_type = '';
}, },
immediate: true, immediate: true,

View File

@@ -72,7 +72,9 @@ import { MESSAGE_EDITOR_MENU_OPTIONS } from 'dashboard/constants/editor';
const createState = ( const createState = (
content, content,
placeholder, placeholder,
// eslint-disable-next-line default-param-last
plugins = [], plugins = [],
// eslint-disable-next-line default-param-last
methods = {}, methods = {},
enabledMenuOptions enabledMenuOptions
) => { ) => {

View File

@@ -32,7 +32,9 @@ const MAXIMUM_FILE_UPLOAD_SIZE = 4; // in MB
const createState = ( const createState = (
content, content,
placeholder, placeholder,
// eslint-disable-next-line default-param-last
plugins = [], plugins = [],
// eslint-disable-next-line default-param-last
methods = {}, methods = {},
enabledMenuOptions enabledMenuOptions
) => { ) => {

View File

@@ -1,8 +1,6 @@
<template> <template>
<div <div
:class=" :class="`status-badge status-badge__${status} rounded-full w-2.5 h-2.5 mr-0.5 rtl:mr-0 rtl:ml-0.5 inline-flex`"
`status-badge status-badge__${status} rounded-full w-2.5 h-2.5 mr-0.5 rtl:mr-0 rtl:ml-0.5 inline-flex`
"
/> />
</template> </template>
<script> <script>

View File

@@ -16,7 +16,7 @@
> >
<div class="items-center flex justify-between last:mt-4"> <div class="items-center flex justify-between last:mt-4">
<span class="text-slate-800 dark:text-slate-100 text-xs font-medium">{{ <span class="text-slate-800 dark:text-slate-100 text-xs font-medium">{{
this.$t('CHAT_LIST.CHAT_SORT.STATUS') $t('CHAT_LIST.CHAT_SORT.STATUS')
}}</span> }}</span>
<filter-item <filter-item
type="status" type="status"
@@ -28,7 +28,7 @@
</div> </div>
<div class="items-center flex justify-between last:mt-4"> <div class="items-center flex justify-between last:mt-4">
<span class="text-slate-800 dark:text-slate-100 text-xs font-medium">{{ <span class="text-slate-800 dark:text-slate-100 text-xs font-medium">{{
this.$t('CHAT_LIST.CHAT_SORT.ORDER_BY') $t('CHAT_LIST.CHAT_SORT.ORDER_BY')
}}</span> }}</span>
<filter-item <filter-item
type="sort" type="sort"

View File

@@ -87,7 +87,7 @@
class="-mt-0.5 align-middle inline-block text-slate-600 dark:text-slate-300" class="-mt-0.5 align-middle inline-block text-slate-600 dark:text-slate-300"
:icon="attachmentIcon" :icon="attachmentIcon"
/> />
{{ this.$t(`${attachmentMessageContent}`) }} {{ $t(`${attachmentMessageContent}`) }}
</span> </span>
<span v-else> <span v-else>
{{ $t('CHAT_LIST.NO_CONTENT') }} {{ $t('CHAT_LIST.NO_CONTENT') }}
@@ -103,7 +103,7 @@
icon="info" icon="info"
/> />
<span> <span>
{{ this.$t(`CHAT_LIST.NO_MESSAGES`) }} {{ $t(`CHAT_LIST.NO_MESSAGES`) }}
</span> </span>
</p> </p>
<div class="conversation--meta flex flex-col absolute right-4 top-4"> <div class="conversation--meta flex flex-col absolute right-4 top-4">

View File

@@ -1,3 +1,4 @@
<!-- eslint-disable vue/no-mutating-props -->
<template> <template>
<woot-modal :show.sync="show" :on-close="onCancel"> <woot-modal :show.sync="show" :on-close="onCancel">
<div class="h-auto overflow-auto flex flex-col"> <div class="h-auto overflow-auto flex flex-col">

View File

@@ -450,16 +450,14 @@ export default {
// label suggestions are not part of the messages list // label suggestions are not part of the messages list
// so we need to handle them separately // so we need to handle them separately
let labelSuggestions = this.conversationPanel.querySelector( let labelSuggestions =
'.label-suggestion' this.conversationPanel.querySelector('.label-suggestion');
);
// if there are unread messages, scroll to the first unread message // if there are unread messages, scroll to the first unread message
if (this.unreadMessageCount > 0) { if (this.unreadMessageCount > 0) {
// capturing only the unread messages // capturing only the unread messages
relevantMessages = this.conversationPanel.querySelectorAll( relevantMessages =
'.message--unread' this.conversationPanel.querySelectorAll('.message--unread');
);
} else if (labelSuggestions) { } else if (labelSuggestions) {
// when scrolling to the bottom, the label suggestions is below the last message // when scrolling to the bottom, the label suggestions is below the last message
// so we scroll there if there are no unread messages // so we scroll there if there are no unread messages

View File

@@ -8,8 +8,10 @@
}" }"
class="shrink-0 rounded-sm inline-flex w-3.5 h-3.5" class="shrink-0 rounded-sm inline-flex w-3.5 h-3.5"
:class="{ :class="{
'bg-red-50 dark:bg-red-700 dark:bg-opacity-30 text-red-500 dark:text-red-600': isUrgent, 'bg-red-50 dark:bg-red-700 dark:bg-opacity-30 text-red-500 dark:text-red-600':
'bg-slate-50 dark:bg-slate-700 text-slate-600 dark:text-slate-200': !isUrgent, isUrgent,
'bg-slate-50 dark:bg-slate-700 text-slate-600 dark:text-slate-200':
!isUrgent,
}" }"
> >
<fluent-icon <fluent-icon

View File

@@ -431,9 +431,8 @@ export default {
const { const {
LAYOUT_TYPES: { CONDENSED }, LAYOUT_TYPES: { CONDENSED },
} = wootConstants; } = wootConstants;
const { const { conversation_display_type: conversationDisplayType = CONDENSED } =
conversation_display_type: conversationDisplayType = CONDENSED, this.uiSettings;
} = this.uiSettings;
return conversationDisplayType !== CONDENSED; return conversationDisplayType !== CONDENSED;
}, },
emojiDialogClassOnExpandedLayoutAndRTLView() { emojiDialogClassOnExpandedLayoutAndRTLView() {

View File

@@ -1,3 +1,4 @@
<!-- eslint-disable vue/no-mutating-props -->
<template> <template>
<woot-modal :show.sync="show" :on-close="onClose" size="modal-big"> <woot-modal :show.sync="show" :on-close="onClose" size="modal-big">
<woot-modal-header <woot-modal-header

View File

@@ -187,8 +187,9 @@ export default {
return ''; return '';
} }
const { screenName, sourceId } = this; const { screenName, sourceId } = this;
return `https://twitter.com/${screenName || return `https://twitter.com/${
this.inbox.name}/status/${sourceId}`; screenName || this.inbox.name
}/status/${sourceId}`;
}, },
linkToStory() { linkToStory() {
if (!this.storyId || !this.storySender) { if (!this.storyId || !this.storySender) {

View File

@@ -57,9 +57,8 @@ export default {
async joinTheCall() { async joinTheCall() {
this.isLoading = true; this.isLoading = true;
try { try {
const { const { data: { authResponse: { authToken } = {} } = {} } =
data: { authResponse: { authToken } = {} } = {}, await DyteAPI.addParticipantToMeeting(this.messageId);
} = await DyteAPI.addParticipantToMeeting(this.messageId);
this.dyteAuthToken = authToken; this.dyteAuthToken = authToken;
} catch (err) { } catch (err) {
this.showAlert(this.$t('INTEGRATION_SETTINGS.DYTE.JOIN_ERROR')); this.showAlert(this.$t('INTEGRATION_SETTINGS.DYTE.JOIN_ERROR'));

View File

@@ -1,3 +1,4 @@
<!-- eslint-disable vue/no-mutating-props -->
<template> <template>
<woot-modal <woot-modal
full-width full-width
@@ -212,8 +213,13 @@ export default {
return this.activeFileType === ALLOWED_FILE_TYPES.AUDIO; return this.activeFileType === ALLOWED_FILE_TYPES.AUDIO;
}, },
senderDetails() { senderDetails() {
const { name, available_name: availableName, avatar_url, thumbnail, id } = const {
this.activeAttachment?.sender || this.attachment?.sender; name,
available_name: availableName,
avatar_url,
thumbnail,
id,
} = this.activeAttachment?.sender || this.attachment?.sender || {};
const currentUserID = this.currentUser?.id; const currentUserID = this.currentUser?.id;
return { return {
name: currentUserID === id ? 'You' : name || availableName || '', name: currentUserID === id ? 'You' : name || availableName || '',

View File

@@ -34,15 +34,13 @@
:option="labelMenuConfig" :option="labelMenuConfig"
:sub-menu-available="!!labels.length" :sub-menu-available="!!labels.length"
> >
<template> <menu-item
<menu-item v-for="label in labels"
v-for="label in labels" :key="label.id"
:key="label.id" :option="generateMenuLabelConfig(label, 'label')"
:option="generateMenuLabelConfig(label, 'label')" variant="label"
variant="label" @click="$emit('assign-label', label)"
@click="$emit('assign-label', label)" />
/>
</template>
</menu-item-with-submenu> </menu-item-with-submenu>
<menu-item-with-submenu <menu-item-with-submenu
:option="agentMenuConfig" :option="agentMenuConfig"

View File

@@ -17,7 +17,7 @@
type="button" type="button"
@click="onAvatarDelete" @click="onAvatarDelete"
> >
{{ this.$t('INBOX_MGMT.DELETE.AVATAR_DELETE_BUTTON_TEXT') }} {{ $t('INBOX_MGMT.DELETE.AVATAR_DELETE_BUTTON_TEXT') }}
</woot-button> </woot-button>
</div> </div>
<label> <label>

View File

@@ -63,8 +63,9 @@
<div v-if="filteredCountriesBySearch.length === 0"> <div v-if="filteredCountriesBySearch.length === 0">
<span <span
class="flex items-center justify-center text-sm text-slate-500 dark:text-slate-300 mt-4" class="flex items-center justify-center text-sm text-slate-500 dark:text-slate-300 mt-4"
>No results found</span
> >
No results found
</span>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,3 +1,4 @@
<!-- eslint-disable vue/no-mutating-props -->
<template> <template>
<modal :show.sync="show" :on-close="closeModal"> <modal :show.sync="show" :on-close="closeModal">
<woot-modal-header :header-title="title" :header-content="message" /> <woot-modal-header :header-title="title" :header-content="message" />

View File

@@ -1,3 +1,4 @@
<!-- eslint-disable vue/no-mutating-props -->
<template> <template>
<modal :show.sync="show" :on-close="onClose"> <modal :show.sync="show" :on-close="onClose">
<woot-modal-header <woot-modal-header

View File

@@ -30,9 +30,7 @@
<hotkey custom-class="min-h-[28px] min-w-[60px] normal-case key"> <hotkey custom-class="min-h-[28px] min-w-[60px] normal-case key">
{{ $t('KEYBOARD_SHORTCUTS.KEYS.ALT_OR_OPTION_KEY') }} {{ $t('KEYBOARD_SHORTCUTS.KEYS.ALT_OR_OPTION_KEY') }}
</hotkey> </hotkey>
<hotkey custom-class="min-h-[28px] w-9 key"> <hotkey custom-class="min-h-[28px] w-9 key"> J </hotkey>
J
</hotkey>
<span <span
class="flex items-center font-semibold text-sm text-slate-800 dark:text-slate-100" class="flex items-center font-semibold text-sm text-slate-800 dark:text-slate-100"
> >
@@ -42,9 +40,7 @@
<hotkey custom-class="min-h-[28px] min-w-[60px] normal-case key"> <hotkey custom-class="min-h-[28px] min-w-[60px] normal-case key">
{{ $t('KEYBOARD_SHORTCUTS.KEYS.ALT_OR_OPTION_KEY') }} {{ $t('KEYBOARD_SHORTCUTS.KEYS.ALT_OR_OPTION_KEY') }}
</hotkey> </hotkey>
<hotkey custom-class="w-9 key"> <hotkey custom-class="w-9 key"> K </hotkey>
K
</hotkey>
</div> </div>
</div> </div>
@@ -59,9 +55,7 @@
<hotkey custom-class="min-h-[28px] min-w-[60px] normal-case key"> <hotkey custom-class="min-h-[28px] min-w-[60px] normal-case key">
{{ $t('KEYBOARD_SHORTCUTS.KEYS.ALT_OR_OPTION_KEY') }} {{ $t('KEYBOARD_SHORTCUTS.KEYS.ALT_OR_OPTION_KEY') }}
</hotkey> </hotkey>
<hotkey custom-class="w-9 key"> <hotkey custom-class="w-9 key"> E </hotkey>
E
</hotkey>
</div> </div>
</div> </div>
<div <div

View File

@@ -97,6 +97,7 @@ class DashboardAudioNotificationHelper {
return conversationAssigneeId === this.currentUserId; return conversationAssigneeId === this.currentUserId;
}; };
// eslint-disable-next-line class-methods-use-this
isMessageFromCurrentConversation = message => { isMessageFromCurrentConversation = message => {
return ( return (
window.WOOT.$store.getters.getSelectedChat?.id === message.conversation_id window.WOOT.$store.getters.getSelectedChat?.id === message.conversation_id

View File

@@ -60,6 +60,7 @@ export const conversationListPageURL = ({
export const isValidURL = value => { export const isValidURL = value => {
/* eslint-disable no-useless-escape */ /* eslint-disable no-useless-escape */
const URL_REGEX = /^https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)$/gm; const URL_REGEX =
/^https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)$/gm;
return URL_REGEX.test(value); return URL_REGEX.test(value);
}; };

View File

@@ -102,6 +102,7 @@ class ActionCableConnector extends BaseActionCableConnector {
this.app.$store.dispatch('updateConversation', data); this.app.$store.dispatch('updateConversation', data);
}; };
// eslint-disable-next-line class-methods-use-this
onLogout = () => AuthAPI.logout(); onLogout = () => AuthAPI.logout();
onMessageCreated = data => { onMessageCreated = data => {
@@ -117,6 +118,7 @@ class ActionCableConnector extends BaseActionCableConnector {
}); });
}; };
// eslint-disable-next-line class-methods-use-this
onReload = () => window.location.reload(); onReload = () => window.location.reload();
onStatusChange = data => { onStatusChange = data => {
@@ -171,6 +173,7 @@ class ActionCableConnector extends BaseActionCableConnector {
}, 30000); }, 30000);
}; };
// eslint-disable-next-line class-methods-use-this
fetchConversationStats = () => { fetchConversationStats = () => {
bus.$emit('fetch_conversation_stats'); bus.$emit('fetch_conversation_stats');
bus.$emit('fetch_overview_reports'); bus.$emit('fetch_overview_reports');
@@ -192,6 +195,7 @@ class ActionCableConnector extends BaseActionCableConnector {
this.app.$store.dispatch('notifications/addNotification', data); this.app.$store.dispatch('notifications/addNotification', data);
}; };
// eslint-disable-next-line class-methods-use-this
onFirstReplyCreated = () => { onFirstReplyCreated = () => {
bus.$emit('fetch_overview_reports'); bus.$emit('fetch_overview_reports');
}; };

View File

@@ -259,7 +259,9 @@ export const isCustomAttribute = (attrs, key) => {
}; };
export const generateCustomAttributes = ( export const generateCustomAttributes = (
// eslint-disable-next-line default-param-last
conversationAttributes = [], conversationAttributes = [],
// eslint-disable-next-line default-param-last
contactAttributes = [], contactAttributes = [],
conversationlabel, conversationlabel,
contactlabel contactlabel

View File

@@ -70,15 +70,8 @@ const getValuesForCountries = (values, countries) => {
export const getValuesForFilter = (filter, params) => { export const getValuesForFilter = (filter, params) => {
const { attribute_key, values } = filter; const { attribute_key, values } = filter;
const { const { languages, countries, agents, inboxes, teams, campaigns, labels } =
languages, params;
countries,
agents,
inboxes,
teams,
campaigns,
labels,
} = params;
switch (attribute_key) { switch (attribute_key) {
case 'status': case 'status':
return getValuesForStatus(values); return getValuesForStatus(values);

View File

@@ -1,7 +1,9 @@
// eslint-disable-next-line default-param-last
export const getCurrentAccount = ({ accounts } = {}, accountId) => { export const getCurrentAccount = ({ accounts } = {}, accountId) => {
return accounts.find(account => account.id === accountId); return accounts.find(account => account.id === accountId);
}; };
// eslint-disable-next-line default-param-last
export const getUserRole = ({ accounts } = {}, accountId) => { export const getUserRole = ({ accounts } = {}, accountId) => {
const currentAccount = getCurrentAccount({ accounts }, accountId) || {}; const currentAccount = getCurrentAccount({ accounts }, accountId) || {};
return currentAccount.role || null; return currentAccount.role || null;

View File

@@ -16,10 +16,8 @@ describe('Helper functions', () => {
const changes = { const changes = {
role: [0, 1], role: [0, 1],
}; };
const { const { changes: extractedChanges, values } =
changes: extractedChanges, extractChangedAccountUserValues(changes);
values,
} = extractChangedAccountUserValues(changes);
expect(extractedChanges).toEqual(['role']); expect(extractedChanges).toEqual(['role']);
expect(values).toEqual(['administrator']); expect(values).toEqual(['administrator']);
}); });
@@ -28,10 +26,8 @@ describe('Helper functions', () => {
const changes = { const changes = {
availability: [0, 2], availability: [0, 2],
}; };
const { const { changes: extractedChanges, values } =
changes: extractedChanges, extractChangedAccountUserValues(changes);
values,
} = extractChangedAccountUserValues(changes);
expect(extractedChanges).toEqual(['availability']); expect(extractedChanges).toEqual(['availability']);
expect(values).toEqual(['busy']); expect(values).toEqual(['busy']);
}); });
@@ -41,10 +37,8 @@ describe('Helper functions', () => {
role: [1, 0], role: [1, 0],
availability: [1, 2], availability: [1, 2],
}; };
const { const { changes: extractedChanges, values } =
changes: extractedChanges, extractChangedAccountUserValues(changes);
values,
} = extractChangedAccountUserValues(changes);
expect(extractedChanges).toEqual(['role', 'availability']); expect(extractedChanges).toEqual(['role', 'availability']);
expect(values).toEqual(['agent', 'busy']); expect(values).toEqual(['agent', 'busy']);
}); });

View File

@@ -97,9 +97,8 @@ describe('removeSignature', () => {
expect(removeSignature(body, signature)).toBe('This is a test\n\n'); expect(removeSignature(body, signature)).toBe('This is a test\n\n');
}); });
it('removes signature if present with spaces and new lines', () => { it('removes signature if present with spaces and new lines', () => {
const { body, signature } = HAS_SIGNATURE[ const { body, signature } =
'signature at end with spaces and new lines' HAS_SIGNATURE['signature at end with spaces and new lines'];
];
expect(removeSignature(body, signature)).toBe('This is a test\n\n'); expect(removeSignature(body, signature)).toBe('This is a test\n\n');
}); });
it('removes signature if present without text before it', () => { it('removes signature if present without text before it', () => {
@@ -129,9 +128,8 @@ describe('replaceSignature', () => {
); );
}); });
it('removes signature if present with spaces and new lines', () => { it('removes signature if present with spaces and new lines', () => {
const { body, signature } = HAS_SIGNATURE[ const { body, signature } =
'signature at end with spaces and new lines' HAS_SIGNATURE['signature at end with spaces and new lines'];
];
expect(replaceSignature(body, signature, NEW_SIGNATURE)).toBe( expect(replaceSignature(body, signature, NEW_SIGNATURE)).toBe(
`This is a test\n\n--\n\n${NEW_SIGNATURE}` `This is a test\n\n--\n\n${NEW_SIGNATURE}`
); );

View File

@@ -169,8 +169,9 @@ export default {
showActionInput(action) { showActionInput(action) {
if (action === 'send_email_to_team' || action === 'send_message') if (action === 'send_email_to_team' || action === 'send_message')
return false; return false;
const type = this.automationActionTypes.find(i => i.key === action) const type = this.automationActionTypes.find(
.inputType; i => i.key === action
).inputType;
return !!type; return !!type;
}, },
resetAction(index) { resetAction(index) {
@@ -264,9 +265,10 @@ export default {
'attributes/getAttributesByModel' 'attributes/getAttributesByModel'
]('conversation_attribute'); ]('conversation_attribute');
const contactCustomAttributesRaw = this.$store.getters[ const contactCustomAttributesRaw =
'attributes/getAttributesByModel' this.$store.getters['attributes/getAttributesByModel'](
]('contact_attribute'); 'contact_attribute'
);
const conversationCustomAttributeTypes = generateCustomAttributeTypes( const conversationCustomAttributeTypes = generateCustomAttributeTypes(
conversationCustomAttributesRaw, conversationCustomAttributesRaw,
'conversation_attribute' 'conversation_attribute'

View File

@@ -19,7 +19,8 @@ describe('uiSettingsMixin', () => {
getUISettings: () => ({ getUISettings: () => ({
enter_to_send_enabled: false, enter_to_send_enabled: false,
is_ct_labels_open: true, is_ct_labels_open: true,
conversation_sidebar_items_order: DEFAULT_CONVERSATION_SIDEBAR_ITEMS_ORDER, conversation_sidebar_items_order:
DEFAULT_CONVERSATION_SIDEBAR_ITEMS_ORDER,
contact_sidebar_items_order: DEFAULT_CONTACT_SIDEBAR_ITEMS_ORDER, contact_sidebar_items_order: DEFAULT_CONTACT_SIDEBAR_ITEMS_ORDER,
}), }),
}; };
@@ -36,7 +37,8 @@ describe('uiSettingsMixin', () => {
expect(wrapper.vm.uiSettings).toEqual({ expect(wrapper.vm.uiSettings).toEqual({
enter_to_send_enabled: false, enter_to_send_enabled: false,
is_ct_labels_open: true, is_ct_labels_open: true,
conversation_sidebar_items_order: DEFAULT_CONVERSATION_SIDEBAR_ITEMS_ORDER, conversation_sidebar_items_order:
DEFAULT_CONVERSATION_SIDEBAR_ITEMS_ORDER,
contact_sidebar_items_order: DEFAULT_CONTACT_SIDEBAR_ITEMS_ORDER, contact_sidebar_items_order: DEFAULT_CONTACT_SIDEBAR_ITEMS_ORDER,
}); });
}); });
@@ -56,7 +58,8 @@ describe('uiSettingsMixin', () => {
uiSettings: { uiSettings: {
enter_to_send_enabled: true, enter_to_send_enabled: true,
is_ct_labels_open: true, is_ct_labels_open: true,
conversation_sidebar_items_order: DEFAULT_CONVERSATION_SIDEBAR_ITEMS_ORDER, conversation_sidebar_items_order:
DEFAULT_CONVERSATION_SIDEBAR_ITEMS_ORDER,
contact_sidebar_items_order: DEFAULT_CONTACT_SIDEBAR_ITEMS_ORDER, contact_sidebar_items_order: DEFAULT_CONTACT_SIDEBAR_ITEMS_ORDER,
}, },
}, },
@@ -80,7 +83,8 @@ describe('uiSettingsMixin', () => {
uiSettings: { uiSettings: {
enter_to_send_enabled: false, enter_to_send_enabled: false,
is_ct_labels_open: false, is_ct_labels_open: false,
conversation_sidebar_items_order: DEFAULT_CONVERSATION_SIDEBAR_ITEMS_ORDER, conversation_sidebar_items_order:
DEFAULT_CONVERSATION_SIDEBAR_ITEMS_ORDER,
contact_sidebar_items_order: DEFAULT_CONTACT_SIDEBAR_ITEMS_ORDER, contact_sidebar_items_order: DEFAULT_CONTACT_SIDEBAR_ITEMS_ORDER,
}, },
}, },

View File

@@ -1,3 +1,4 @@
<!-- eslint-disable vue/no-mutating-props -->
<template> <template>
<woot-modal :show.sync="show" :on-close="onClose"> <woot-modal :show.sync="show" :on-close="onClose">
<woot-modal-header <woot-modal-header

View File

@@ -1,3 +1,4 @@
<!-- eslint-disable vue/no-mutating-props -->
<template> <template>
<modal :show.sync="show" :on-close="onClose"> <modal :show.sync="show" :on-close="onClose">
<woot-modal-header <woot-modal-header

View File

@@ -48,7 +48,7 @@
v-if="enabledOptions['copy']" v-if="enabledOptions['copy']"
:option="{ :option="{
icon: 'clipboard', icon: 'clipboard',
label: this.$t('CONVERSATION.CONTEXT_MENU.COPY'), label: $t('CONVERSATION.CONTEXT_MENU.COPY'),
}" }"
variant="icon" variant="icon"
@click="handleCopy" @click="handleCopy"
@@ -57,7 +57,7 @@
v-if="enabledOptions['copy']" v-if="enabledOptions['copy']"
:option="{ :option="{
icon: 'translate', icon: 'translate',
label: this.$t('CONVERSATION.CONTEXT_MENU.TRANSLATE'), label: $t('CONVERSATION.CONTEXT_MENU.TRANSLATE'),
}" }"
variant="icon" variant="icon"
@click="handleTranslate" @click="handleTranslate"
@@ -66,7 +66,7 @@
<menu-item <menu-item
:option="{ :option="{
icon: 'link', icon: 'link',
label: this.$t('CONVERSATION.CONTEXT_MENU.COPY_PERMALINK'), label: $t('CONVERSATION.CONTEXT_MENU.COPY_PERMALINK'),
}" }"
variant="icon" variant="icon"
@click="copyLinkToMessage" @click="copyLinkToMessage"
@@ -75,9 +75,7 @@
v-if="enabledOptions['cannedResponse']" v-if="enabledOptions['cannedResponse']"
:option="{ :option="{
icon: 'comment-add', icon: 'comment-add',
label: this.$t( label: $t('CONVERSATION.CONTEXT_MENU.CREATE_A_CANNED_RESPONSE'),
'CONVERSATION.CONTEXT_MENU.CREATE_A_CANNED_RESPONSE'
),
}" }"
variant="icon" variant="icon"
@click="showCannedResponseModal" @click="showCannedResponseModal"
@@ -87,7 +85,7 @@
v-if="enabledOptions['delete']" v-if="enabledOptions['delete']"
:option="{ :option="{
icon: 'delete', icon: 'delete',
label: this.$t('CONVERSATION.CONTEXT_MENU.DELETE'), label: $t('CONVERSATION.CONTEXT_MENU.DELETE'),
}" }"
variant="icon" variant="icon"
@click="openDeleteModal" @click="openDeleteModal"

View File

@@ -3,7 +3,8 @@
<div <div
ref="content" ref="content"
:class="{ :class="{
'shrink-container after:shrink-gradient-light dark:after:shrink-gradient-dark': shrink, 'shrink-container after:shrink-gradient-light dark:after:shrink-gradient-dark':
shrink,
}" }"
> >
<slot /> <slot />

View File

@@ -5,7 +5,7 @@
</div> </div>
<div class="conversation-details"> <div class="conversation-details">
<div class="meta-wrap"> <div class="meta-wrap">
<div class="flex-container "> <div class="flex-container">
<woot-label <woot-label
class="conversation-id" class="conversation-id"
:title="`#${id}`" :title="`#${id}`"

View File

@@ -70,7 +70,9 @@ export default {
background: white; background: white;
&.is-focused { &.is-focused {
box-shadow: 0 0 0 1px var(--color-woot), 0 0 2px 2px var(--w-100); box-shadow:
0 0 0 1px var(--color-woot),
0 0 2px 2px var(--w-100);
} }
} }

View File

@@ -87,9 +87,8 @@ export default {
return conversationDisplayType; return conversationDisplayType;
}, },
previouslyUsedSidebarView() { previouslyUsedSidebarView() {
const { const { previously_used_sidebar_view: showSecondarySidebar } =
previously_used_sidebar_view: showSecondarySidebar, this.uiSettings;
} = this.uiSettings;
return showSecondarySidebar; return showSecondarySidebar;
}, },
}, },

View File

@@ -56,8 +56,9 @@ export default {
methods: { methods: {
setAppearance(theme) { setAppearance(theme) {
LocalStorage.set(LOCAL_STORAGE_KEYS.COLOR_SCHEME, theme); LocalStorage.set(LOCAL_STORAGE_KEYS.COLOR_SCHEME, theme);
const isOSOnDarkMode = window.matchMedia('(prefers-color-scheme: dark)') const isOSOnDarkMode = window.matchMedia(
.matches; '(prefers-color-scheme: dark)'
).matches;
setColorTheme(isOSOnDarkMode); setColorTheme(isOSOnDarkMode);
}, },
}, },

View File

@@ -30,13 +30,10 @@ export default {
appearanceHotKeys, appearanceHotKeys,
goToCommandHotKeys, goToCommandHotKeys,
], ],
data() {
return {
placeholder: this.$t('COMMAND_BAR.SEARCH_PLACEHOLDER'),
};
},
computed: { computed: {
placeholder() {
return this.$t('COMMAND_BAR.SEARCH_PLACEHOLDER');
},
accountId() { accountId() {
return this.$store.getters.getCurrentAccountId; return this.$store.getters.getCurrentAccountId;
}, },
@@ -64,9 +61,8 @@ export default {
this.$refs.ninjakeys.data = this.hotKeys; this.$refs.ninjakeys.data = this.hotKeys;
}, },
onSelected(item) { onSelected(item) {
const { const { detail: { action: { title = null, section = null } = {} } = {} } =
detail: { action: { title = null, section = null } = {} } = {}, item;
} = item;
this.$track(GENERAL_EVENTS.COMMAND_BAR, { this.$track(GENERAL_EVENTS.COMMAND_BAR, {
section, section,
action: title, action: title,

View File

@@ -407,9 +407,10 @@ export default {
const params = { const params = {
countries: countries, countries: countries,
filterTypes: contactFilterItems, filterTypes: contactFilterItems,
allCustomAttributes: this.$store.getters[ allCustomAttributes:
'attributes/getAttributesByModel' this.$store.getters['attributes/getAttributesByModel'](
]('contact_attribute'), 'contact_attribute'
),
}; };
return params; return params;
}, },

View File

@@ -1,3 +1,4 @@
<!-- eslint-disable vue/v-slot-style -->
<template> <template>
<div class="bg-white dark:bg-slate-900"> <div class="bg-white dark:bg-slate-900">
<div class="multiselect-wrap--small"> <div class="multiselect-wrap--small">

View File

@@ -117,10 +117,8 @@ export default {
if (!this.conversationAttributes.browser) { if (!this.conversationAttributes.browser) {
return ''; return '';
} }
const { const { platform_name: platformName, platform_version: platformVersion } =
platform_name: platformName, this.conversationAttributes.browser;
platform_version: platformVersion,
} = this.conversationAttributes.browser;
return `${platformName || ''} ${platformVersion || ''}`; return `${platformName || ''} ${platformVersion || ''}`;
}, },
ipAddress() { ipAddress() {

View File

@@ -87,16 +87,14 @@ export default {
const { const {
LAYOUT_TYPES: { CONDENSED }, LAYOUT_TYPES: { CONDENSED },
} = wootConstants; } = wootConstants;
const { const { conversation_display_type: conversationDisplayType = CONDENSED } =
conversation_display_type: conversationDisplayType = CONDENSED, this.uiSettings;
} = this.uiSettings;
return conversationDisplayType !== CONDENSED; return conversationDisplayType !== CONDENSED;
}, },
isContactPanelOpen() { isContactPanelOpen() {
if (this.currentChat.id) { if (this.currentChat.id) {
const { const { is_contact_sidebar_open: isContactSidebarOpen } =
is_contact_sidebar_open: isContactSidebarOpen, this.uiSettings;
} = this.uiSettings;
return isContactSidebarOpen; return isContactSidebarOpen;
} }
return false; return false;
@@ -127,7 +125,8 @@ export default {
toggleConversationLayout() { toggleConversationLayout() {
const { LAYOUT_TYPES } = wootConstants; const { LAYOUT_TYPES } = wootConstants;
const { const {
conversation_display_type: conversationDisplayType = LAYOUT_TYPES.CONDENSED, conversation_display_type:
conversationDisplayType = LAYOUT_TYPES.CONDENSED,
} = this.uiSettings; } = this.uiSettings;
const newViewType = const newViewType =
conversationDisplayType === LAYOUT_TYPES.CONDENSED conversationDisplayType === LAYOUT_TYPES.CONDENSED

View File

@@ -1,5 +1,5 @@
<template> <template>
<div class="macro button secondary clear "> <div class="macro button secondary clear">
<span class="overflow-hidden whitespace-nowrap text-ellipsis">{{ <span class="overflow-hidden whitespace-nowrap text-ellipsis">{{
macro.name macro.name
}}</span> }}</span>

View File

@@ -117,9 +117,7 @@
/> />
<div class="w-full"> <div class="w-full">
<label> <label> Social Profiles </label>
Social Profiles
</label>
<div <div
v-for="socialProfile in socialProfileKeys" v-for="socialProfile in socialProfileKeys"
:key="socialProfile.key" :key="socialProfile.key"

View File

@@ -1,3 +1,4 @@
<!-- eslint-disable vue/no-mutating-props -->
<template> <template>
<woot-modal :show.sync="show" :on-close="onCancel" modal-type="right-aligned"> <woot-modal :show.sync="show" :on-close="onCancel" modal-type="right-aligned">
<div class="h-auto overflow-auto flex flex-col"> <div class="h-auto overflow-auto flex flex-col">

View File

@@ -1,10 +1,11 @@
<!-- eslint-disable vue/no-mutating-props -->
<template> <template>
<woot-modal :show.sync="show" :on-close="onCancel" modal-type="right-aligned"> <woot-modal :show.sync="show" :on-close="onCancel" modal-type="right-aligned">
<div class="h-auto overflow-auto flex flex-col"> <div class="h-auto overflow-auto flex flex-col">
<woot-modal-header <woot-modal-header
:header-title=" :header-title="`${$t('EDIT_CONTACT.TITLE')} - ${
`${$t('EDIT_CONTACT.TITLE')} - ${contact.name || contact.email}` contact.name || contact.email
" }`"
:header-content="$t('EDIT_CONTACT.DESC')" :header-content="$t('EDIT_CONTACT.DESC')"
/> />
<contact-form <contact-form

View File

@@ -1,3 +1,4 @@
<!-- eslint-disable vue/no-mutating-props -->
<template> <template>
<woot-modal :show.sync="show" :on-close="onCancel"> <woot-modal :show.sync="show" :on-close="onCancel">
<div class="h-auto overflow-auto flex flex-col"> <div class="h-auto overflow-auto flex flex-col">

View File

@@ -1,3 +1,4 @@
<!-- eslint-disable vue/no-mutating-props -->
<template> <template>
<div> <div>
<woot-delete-modal <woot-delete-modal

View File

@@ -1,3 +1,4 @@
<!-- eslint-disable vue/no-mutating-props -->
<template> <template>
<modal :show.sync="show" :on-close="onClose"> <modal :show.sync="show" :on-close="onClose">
<woot-modal-header <woot-modal-header

View File

@@ -10,7 +10,7 @@
{{ ` / ` }} {{ ` / ` }}
{{ {{
category || category ||
$t('HELP_CENTER.ARTICLE_SEARCH_RESULT.ARTICLE_SEARCH_RESULT') $t('HELP_CENTER.ARTICLE_SEARCH_RESULT.ARTICLE_SEARCH_RESULT')
}} }}
</p> </p>
<div class="action-buttons"> <div class="action-buttons">

View File

@@ -104,9 +104,8 @@ export default {
isFetching: 'portals/isFetchingPortals', isFetching: 'portals/isFetchingPortals',
}), }),
isSidebarOpen() { isSidebarOpen() {
const { const { show_help_center_secondary_sidebar: showSecondarySidebar } =
show_help_center_secondary_sidebar: showSecondarySidebar, this.uiSettings;
} = this.uiSettings;
return showSecondarySidebar; return showSecondarySidebar;
}, },
showHelpCenterSidebar() { showHelpCenterSidebar() {

View File

@@ -27,13 +27,11 @@
<ul> <ul>
<li v-for="locale in locales" :key="locale.code"> <li v-for="locale in locales" :key="locale.code">
<woot-button <woot-button
:variant=" :variant="`locale-item ${
`locale-item ${ isLocaleActive(locale.code, activePortalSlug)
isLocaleActive(locale.code, activePortalSlug) ? 'smooth'
? 'smooth' : 'clear'
: 'clear' }`"
}`
"
size="large" size="large"
color-scheme="secondary" color-scheme="secondary"
@click="event => onClick(event, locale.code, portal)" @click="event => onClick(event, locale.code, portal)"

View File

@@ -1,3 +1,4 @@
<!-- eslint-disable vue/no-mutating-props -->
<template> <template>
<woot-modal :show.sync="show" :on-close="onClose"> <woot-modal :show.sync="show" :on-close="onClose">
<woot-modal-header <woot-modal-header

View File

@@ -1,3 +1,4 @@
<!-- eslint-disable vue/no-mutating-props -->
<template> <template>
<woot-modal :show.sync="show" :on-close="onClose"> <woot-modal :show.sync="show" :on-close="onClose">
<woot-modal-header <woot-modal-header

View File

@@ -1,5 +1,5 @@
<template> <template>
<div class="flex-col py-2 px-2.5 overflow-auto h-full flex "> <div class="flex-col py-2 px-2.5 overflow-auto h-full flex">
<woot-button <woot-button
v-for="notificationItem in notifications" v-for="notificationItem in notifications"
v-show="!isLoading" v-show="!isLoading"
@@ -21,7 +21,7 @@
class="flex-col ml-2.5 overflow-hidden w-full flex justify-between" class="flex-col ml-2.5 overflow-hidden w-full flex justify-between"
> >
<div class="flex justify-between"> <div class="flex justify-between">
<div class="items-center flex "> <div class="items-center flex">
<span class="font-bold text-slate-800 dark:text-slate-100"> <span class="font-bold text-slate-800 dark:text-slate-100">
{{ {{
`#${ `#${
@@ -50,7 +50,7 @@
/> />
</div> </div>
</div> </div>
<div class="w-full flex "> <div class="w-full flex">
<span <span
class="text-slate-700 dark:text-slate-200 font-normal overflow-hidden whitespace-nowrap text-ellipsis" class="text-slate-700 dark:text-slate-200 font-normal overflow-hidden whitespace-nowrap text-ellipsis"
> >

View File

@@ -135,7 +135,7 @@ import alertMixin from 'shared/mixins/alertMixin';
import configMixin from 'shared/mixins/configMixin'; import configMixin from 'shared/mixins/configMixin';
import accountMixin from '../../../../mixins/account'; import accountMixin from '../../../../mixins/account';
import { FEATURE_FLAGS } from '../../../../featureFlags'; import { FEATURE_FLAGS } from '../../../../featureFlags';
const semver = require('semver'); import semver from 'semver';
import uiSettingsMixin from 'dashboard/mixins/uiSettings'; import uiSettingsMixin from 'dashboard/mixins/uiSettings';
import { getLanguageDirection } from 'dashboard/components/widgets/conversation/advancedFilterItems/languages'; import { getLanguageDirection } from 'dashboard/components/widgets/conversation/advancedFilterItems/languages';

View File

@@ -50,8 +50,8 @@
<woot-submit-button <woot-submit-button
:disabled=" :disabled="
$v.agentEmail.$invalid || $v.agentEmail.$invalid ||
$v.agentName.$invalid || $v.agentName.$invalid ||
uiFlags.isCreating uiFlags.isCreating
" "
:button-text="$t('AGENT_MGMT.ADD.FORM.SUBMIT')" :button-text="$t('AGENT_MGMT.ADD.FORM.SUBMIT')"
:loading="uiFlags.isCreating" :loading="uiFlags.isCreating"
@@ -130,9 +130,8 @@ export default {
this.showAlert(this.$t('AGENT_MGMT.ADD.API.SUCCESS_MESSAGE')); this.showAlert(this.$t('AGENT_MGMT.ADD.API.SUCCESS_MESSAGE'));
this.onClose(); this.onClose();
} catch (error) { } catch (error) {
const { const { response: { data: { error: errorResponse = '' } = {} } = {} } =
response: { data: { error: errorResponse = '' } = {} } = {}, error;
} = error;
let errorMessage = ''; let errorMessage = '';
if (error.response.status === 422) { if (error.response.status === 422) {
errorMessage = this.$t('AGENT_MGMT.ADD.API.EXIST_MESSAGE'); errorMessage = this.$t('AGENT_MGMT.ADD.API.EXIST_MESSAGE');

View File

@@ -51,8 +51,8 @@
<woot-submit-button <woot-submit-button
:disabled=" :disabled="
$v.agentType.$invalid || $v.agentType.$invalid ||
$v.agentName.$invalid || $v.agentName.$invalid ||
uiFlags.isUpdating uiFlags.isUpdating
" "
:button-text="$t('AGENT_MGMT.EDIT.FORM.SUBMIT')" :button-text="$t('AGENT_MGMT.EDIT.FORM.SUBMIT')"
:loading="uiFlags.isUpdating" :loading="uiFlags.isUpdating"

View File

@@ -77,6 +77,12 @@ export default {
TableFooter, TableFooter,
}, },
mixins: [alertMixin, timeMixin], mixins: [alertMixin, timeMixin],
beforeRouteEnter(to, from, next) {
// Fetch Audit Logs on page load without manual refresh
next(vm => {
vm.fetchAuditLogs();
});
},
data() { data() {
return { return {
loading: {}, loading: {},
@@ -85,12 +91,6 @@ export default {
}, },
}; };
}, },
beforeRouteEnter(to, from, next) {
// Fetch Audit Logs on page load without manual refresh
next(vm => {
vm.fetchAuditLogs();
});
},
computed: { computed: {
...mapGetters({ ...mapGetters({
records: 'auditlogs/getAuditLogs', records: 'auditlogs/getAuditLogs',

View File

@@ -38,8 +38,8 @@
<woot-submit-button <woot-submit-button
:disabled=" :disabled="
$v.content.$invalid || $v.content.$invalid ||
$v.shortCode.$invalid || $v.shortCode.$invalid ||
addCanned.showLoading addCanned.showLoading
" "
:button-text="$t('CANNED_MGMT.ADD.FORM.SUBMIT')" :button-text="$t('CANNED_MGMT.ADD.FORM.SUBMIT')"
:loading="addCanned.showLoading" :loading="addCanned.showLoading"

View File

@@ -35,8 +35,8 @@
<woot-submit-button <woot-submit-button
:disabled=" :disabled="
$v.content.$invalid || $v.content.$invalid ||
$v.shortCode.$invalid || $v.shortCode.$invalid ||
editCanned.showLoading editCanned.showLoading
" "
:button-text="$t('CANNED_MGMT.EDIT.FORM.SUBMIT')" :button-text="$t('CANNED_MGMT.EDIT.FORM.SUBMIT')"
:loading="editCanned.showLoading" :loading="editCanned.showLoading"

View File

@@ -61,7 +61,7 @@
class="button hollow primary" class="button hollow primary"
:to="{ :to="{
name: 'settings_inbox_show', name: 'settings_inbox_show',
params: { inboxId: this.$route.params.inbox_id }, params: { inboxId: $route.params.inbox_id },
}" }"
> >
{{ $t('INBOX_MGMT.FINISH.MORE_SETTINGS') }} {{ $t('INBOX_MGMT.FINISH.MORE_SETTINGS') }}
@@ -70,7 +70,7 @@
class="button success" class="button success"
:to="{ :to="{
name: 'inbox_dashboard', name: 'inbox_dashboard',
params: { inboxId: this.$route.params.inbox_id }, params: { inboxId: $route.params.inbox_id },
}" }"
> >
{{ $t('INBOX_MGMT.FINISH.BUTTON_TEXT') }} {{ $t('INBOX_MGMT.FINISH.BUTTON_TEXT') }}

View File

@@ -51,9 +51,7 @@
<span v-if="item.channel_type === 'Channel::Whatsapp'"> <span v-if="item.channel_type === 'Channel::Whatsapp'">
Whatsapp Whatsapp
</span> </span>
<span v-if="item.channel_type === 'Channel::Sms'"> <span v-if="item.channel_type === 'Channel::Sms'"> Sms </span>
Sms
</span>
<span v-if="item.channel_type === 'Channel::Email'"> <span v-if="item.channel_type === 'Channel::Email'">
Email Email
</span> </span>

Some files were not shown because too many files have changed in this diff Show More