From 2c94c890772de324248ee1306c80ff6f47c4598c Mon Sep 17 00:00:00 2001
From: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
Date: Sat, 29 Jun 2024 01:21:27 +0530
Subject: [PATCH 01/22] feat: Add video message viewer in agent widget bubble
(#9691)
Fixes https://linear.app/chatwoot/issue/CW-3384/video-message-display-issue
---
.../widget/components/AgentMessage.vue | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/app/javascript/widget/components/AgentMessage.vue b/app/javascript/widget/components/AgentMessage.vue
index eb64e0c36..c38726031 100755
--- a/app/javascript/widget/components/AgentMessage.vue
+++ b/app/javascript/widget/components/AgentMessage.vue
@@ -30,7 +30,7 @@
/>
+
+
+
@@ -84,6 +92,7 @@ import AgentMessageBubble from 'widget/components/AgentMessageBubble.vue';
import MessageReplyButton from 'widget/components/MessageReplyButton.vue';
import timeMixin from 'dashboard/mixins/time';
import ImageBubble from 'widget/components/ImageBubble.vue';
+import VideoBubble from 'widget/components/VideoBubble.vue';
import FileBubble from 'widget/components/FileBubble.vue';
import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
import { MESSAGE_TYPE } from 'widget/helpers/constants';
@@ -100,6 +109,7 @@ export default {
components: {
AgentMessageBubble,
ImageBubble,
+ VideoBubble,
Thumbnail,
UserMessage,
FileBubble,
@@ -120,6 +130,7 @@ export default {
data() {
return {
hasImageError: false,
+ hasVideoError: false,
};
},
computed: {
@@ -215,15 +226,20 @@ export default {
watch: {
message() {
this.hasImageError = false;
+ this.hasVideoError = false;
},
},
mounted() {
this.hasImageError = false;
+ this.hasVideoError = false;
},
methods: {
onImageLoadError() {
this.hasImageError = true;
},
+ onVideoLoadError() {
+ this.hasVideoError = true;
+ },
toggleReply() {
emitter.emit(BUS_EVENTS.TOGGLE_REPLY_TO_MESSAGE, this.message);
},
From 46621b098316260d6db97c87c126dd17bd118ad9 Mon Sep 17 00:00:00 2001
From: Sojan Jose
Date: Fri, 28 Jun 2024 12:52:48 -0700
Subject: [PATCH 02/22] chore: Add permissions to auth data (#9695)
This API change sets the foundation for an upcoming frontend update, transitioning from a role-based model to a permission-based model. This new approach will determine eligibility for various actions and UI elements based on specific permissions rather than roles, enhancing flexibility and security in user access management.
---
app/models/account_user.rb | 4 ++++
app/views/api/v1/models/_user.json.jbuilder | 2 ++
spec/controllers/devise/session_controller_spec.rb | 11 +++++++++++
spec/models/account_user_spec.rb | 11 +++++++++++
4 files changed, 28 insertions(+)
diff --git a/app/models/account_user.rb b/app/models/account_user.rb
index 78b874334..176d52102 100644
--- a/app/models/account_user.rb
+++ b/app/models/account_user.rb
@@ -49,6 +49,10 @@ class AccountUser < ApplicationRecord
::Agents::DestroyJob.perform_later(account, user)
end
+ def permissions
+ administrator? ? ['administrator'] : ['agent']
+ end
+
def push_event_data
{
id: id,
diff --git a/app/views/api/v1/models/_user.json.jbuilder b/app/views/api/v1/models/_user.json.jbuilder
index 74df836c0..0e8c95adb 100644
--- a/app/views/api/v1/models/_user.json.jbuilder
+++ b/app/views/api/v1/models/_user.json.jbuilder
@@ -14,6 +14,7 @@ json.provider resource.provider
json.pubsub_token resource.pubsub_token
json.custom_attributes resource.custom_attributes if resource.custom_attributes.present?
json.role resource.active_account_user&.role
+json.permissions resource.active_account_user&.permissions
json.ui_settings resource.ui_settings
json.uid resource.uid
json.type resource.type
@@ -24,6 +25,7 @@ json.accounts do
json.status account_user.account.status
json.active_at account_user.active_at
json.role account_user.role
+ json.permissions account_user.permissions
# the actual availability user has configured
json.availability account_user.availability
# availability derived from presence
diff --git a/spec/controllers/devise/session_controller_spec.rb b/spec/controllers/devise/session_controller_spec.rb
index 42f8b8bd8..ad6d76bf9 100644
--- a/spec/controllers/devise/session_controller_spec.rb
+++ b/spec/controllers/devise/session_controller_spec.rb
@@ -41,6 +41,17 @@ RSpec.describe 'Session', type: :request do
expect(response).to have_http_status(:success)
expect(response.body).to include(user_with_new_pwd.email)
end
+
+ it 'returns the permission of the user' do
+ params = { email: user.email, password: 'Password1!' }
+
+ post new_user_session_url,
+ params: params,
+ as: :json
+
+ expect(response).to have_http_status(:success)
+ expect(response.parsed_body['data']['permissions']).to eq(['agent'])
+ end
end
context 'when it is invalid sso auth token' do
diff --git a/spec/models/account_user_spec.rb b/spec/models/account_user_spec.rb
index 2b8ef790a..e5a560fe9 100644
--- a/spec/models/account_user_spec.rb
+++ b/spec/models/account_user_spec.rb
@@ -17,6 +17,17 @@ RSpec.describe AccountUser do
end
end
+ describe 'permissions' do
+ it 'returns the right permissions' do
+ expect(account_user.permissions).to eq(['agent'])
+ end
+
+ it 'returns the right permissions for administrator' do
+ account_user.administrator!
+ expect(account_user.permissions).to eq(['administrator'])
+ end
+ end
+
describe 'destroy call agent::destroy service' do
it 'gets created with the right default settings' do
create(:conversation, account: account_user.account, assignee: account_user.user, inbox: inbox)
From 5520bf68f37c5bbc189f5c4bbbdc325e1a4fad22 Mon Sep 17 00:00:00 2001
From: Shivam Mishra
Date: Mon, 1 Jul 2024 11:11:57 +0530
Subject: [PATCH 03/22] feat: disable scripts on password reset page (#9693)
---
app/controllers/dashboard_controller.rb | 12 +++++++++++-
app/javascript/v3/views/index.js | 12 ++++++++----
2 files changed, 19 insertions(+), 5 deletions(-)
diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb
index e656c2550..332f1528f 100644
--- a/app/controllers/dashboard_controller.rb
+++ b/app/controllers/dashboard_controller.rb
@@ -37,7 +37,7 @@ class DashboardController < ActionController::Base
end
def set_dashboard_scripts
- @dashboard_scripts = GlobalConfig.get_value('DASHBOARD_SCRIPTS')
+ @dashboard_scripts = sensitive_path? ? nil : GlobalConfig.get_value('DASHBOARD_SCRIPTS')
end
def ensure_installation_onboarding
@@ -75,4 +75,14 @@ class DashboardController < ActionController::Base
'application'
end
end
+
+ def sensitive_path?
+ # dont load dashboard scripts on sensitive paths like password reset
+ sensitive_paths = [edit_user_password_path].freeze
+
+ # remove app prefix
+ current_path = request.path.gsub(%r{^/app}, '')
+
+ sensitive_paths.include?(current_path)
+ end
end
diff --git a/app/javascript/v3/views/index.js b/app/javascript/v3/views/index.js
index 57da18116..dd30f0372 100644
--- a/app/javascript/v3/views/index.js
+++ b/app/javascript/v3/views/index.js
@@ -6,12 +6,16 @@ import { validateRouteAccess } from '../helpers/RouteHelper';
export const router = new VueRouter({ mode: 'history', routes });
+const sensitiveRouteNames = ['auth_password_edit'];
+
export const initalizeRouter = () => {
router.beforeEach((to, _, next) => {
- AnalyticsHelper.page(to.name || '', {
- path: to.path,
- name: to.name,
- });
+ if (!sensitiveRouteNames.includes(to.name)) {
+ AnalyticsHelper.page(to.name || '', {
+ path: to.path,
+ name: to.name,
+ });
+ }
return validateRouteAccess(to, next, window.chatwootConfig);
});
From cc4851b19d1e3aedced341b01ff3bee5e43e0983 Mon Sep 17 00:00:00 2001
From: Sojan Jose
Date: Wed, 3 Jul 2024 15:13:16 -0700
Subject: [PATCH 04/22] chore: Move frontend authorization to permission based
system (#9709)
We previously relied on user roles to determine whether to render
specific routes in our frontend components. A permissions-based model is replacing this approach.
Follow up: #9695
Co-authored-by: Pranav
---
.../dashboard/components/layout/Sidebar.vue | 11 ++-
.../layout/config/sidebarItems/primaryMenu.js | 9 +-
.../layout/config/sidebarItems/settings.js | 46 +++++++++-
.../layout/sidebarComponents/Secondary.vue | 26 +++---
.../sidebarComponents/SecondaryNavItem.vue | 47 +++++-----
.../dashboard/components/policy.vue | 23 +++++
.../dashboard/helper/permissionsHelper.js | 34 +++++++
.../dashboard/helper/routeHelpers.js | 23 ++---
.../helper/specs/permissionsHelper.spec.js | 84 ++++++++++++++++++
.../helper/specs/routeHelpers.spec.js | 66 +++++++-------
.../dashboard/modules/search/search.routes.js | 4 +-
.../routes/dashboard/contacts/routes.js | 16 +++-
.../conversation/conversation.routes.js | 64 ++++++++++----
.../routes/dashboard/dashboard.routes.js | 4 +-
.../dashboard/helpcenter/helpcenter.routes.js | 88 ++++++++++++++-----
.../routes/dashboard/inbox/routes.js | 8 +-
.../routes/dashboard/notifications/routes.js | 4 +-
.../settings/account/account.routes.js | 8 +-
.../settings/agentBots/agentBot.routes.js | 16 +++-
.../dashboard/settings/agents/agent.routes.js | 5 +-
.../settings/attributes/attributes.routes.js | 5 +-
.../settings/auditlogs/audit.routes.js | 5 +-
.../settings/automation/automation.routes.js | 5 +-
.../settings/billing/billing.routes.js | 8 +-
.../settings/campaigns/campaigns.routes.js | 8 +-
.../settings/canned/canned.routes.js | 5 +-
.../dashboard/settings/inbox/inbox.routes.js | 25 ++++--
.../integrationapps/integrations.routes.js | 8 +-
.../integrations/integrations.routes.js | 20 +++--
.../settings/labels/labels.routes.js | 8 +-
.../settings/macros/macros.routes.js | 12 ++-
.../settings/profile/profile.routes.js | 8 +-
.../settings/reports/reports.routes.js | 36 ++++++--
.../dashboard/settings/settings.routes.js | 4 +-
.../dashboard/settings/sla/sla.routes.js | 8 +-
.../dashboard/settings/teams/teams.routes.js | 29 ++++--
app/javascript/dashboard/routes/index.js | 31 +------
37 files changed, 582 insertions(+), 229 deletions(-)
create mode 100644 app/javascript/dashboard/components/policy.vue
create mode 100644 app/javascript/dashboard/helper/permissionsHelper.js
create mode 100644 app/javascript/dashboard/helper/specs/permissionsHelper.spec.js
diff --git a/app/javascript/dashboard/components/layout/Sidebar.vue b/app/javascript/dashboard/components/layout/Sidebar.vue
index 0f3a1a857..4ccaa97df 100644
--- a/app/javascript/dashboard/components/layout/Sidebar.vue
+++ b/app/javascript/dashboard/components/layout/Sidebar.vue
@@ -20,7 +20,7 @@
:teams="teams"
:custom-views="customViews"
:menu-config="activeSecondaryMenu"
- :current-role="currentRole"
+ :current-user="currentUser"
:is-on-chatwoot-cloud="isOnChatwootCloud"
@add-label="showAddLabelPopup"
@toggle-accounts="toggleAccountModal"
@@ -37,7 +37,8 @@ import alertMixin from 'shared/mixins/alertMixin';
import PrimarySidebar from './sidebarComponents/Primary.vue';
import SecondarySidebar from './sidebarComponents/Secondary.vue';
import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
-import router from '../../routes';
+import router, { routesWithPermissions } from '../../routes';
+import { hasPermissions } from '../../helper/permissionsHelper';
export default {
components: {
@@ -98,9 +99,13 @@ export default {
return getSidebarItems(this.accountId);
},
primaryMenuItems() {
+ const userPermissions = this.currentUser.permissions;
const menuItems = this.sideMenuConfig.primaryMenu;
return menuItems.filter(menuItem => {
- const isAvailableForTheUser = menuItem.roles.includes(this.currentRole);
+ const isAvailableForTheUser = hasPermissions(
+ routesWithPermissions[menuItem.toStateName],
+ userPermissions
+ );
if (!isAvailableForTheUser) {
return false;
diff --git a/app/javascript/dashboard/components/layout/config/sidebarItems/primaryMenu.js b/app/javascript/dashboard/components/layout/config/sidebarItems/primaryMenu.js
index 7513e3d1c..92b8765c6 100644
--- a/app/javascript/dashboard/components/layout/config/sidebarItems/primaryMenu.js
+++ b/app/javascript/dashboard/components/layout/config/sidebarItems/primaryMenu.js
@@ -9,7 +9,6 @@ const primaryMenuItems = accountId => [
featureFlag: FEATURE_FLAGS.INBOX_VIEW,
toState: frontendURL(`accounts/${accountId}/inbox-view`),
toStateName: 'inbox_view',
- roles: ['administrator', 'agent'],
},
{
icon: 'chat',
@@ -17,7 +16,6 @@ const primaryMenuItems = accountId => [
label: 'CONVERSATIONS',
toState: frontendURL(`accounts/${accountId}/dashboard`),
toStateName: 'home',
- roles: ['administrator', 'agent'],
},
{
icon: 'book-contacts',
@@ -26,7 +24,6 @@ const primaryMenuItems = accountId => [
featureFlag: FEATURE_FLAGS.CRM,
toState: frontendURL(`accounts/${accountId}/contacts`),
toStateName: 'contacts_dashboard',
- roles: ['administrator', 'agent'],
},
{
icon: 'arrow-trending-lines',
@@ -34,8 +31,7 @@ const primaryMenuItems = accountId => [
label: 'REPORTS',
featureFlag: FEATURE_FLAGS.REPORTS,
toState: frontendURL(`accounts/${accountId}/reports`),
- toStateName: 'settings_account_reports',
- roles: ['administrator'],
+ toStateName: 'account_overview_reports',
},
{
icon: 'megaphone',
@@ -44,7 +40,6 @@ const primaryMenuItems = accountId => [
featureFlag: FEATURE_FLAGS.CAMPAIGNS,
toState: frontendURL(`accounts/${accountId}/campaigns`),
toStateName: 'ongoing_campaigns',
- roles: ['administrator'],
},
{
icon: 'library',
@@ -54,7 +49,6 @@ const primaryMenuItems = accountId => [
alwaysVisibleOnChatwootInstances: true,
toState: frontendURL(`accounts/${accountId}/portals`),
toStateName: 'default_portal_articles',
- roles: ['administrator'],
},
{
icon: 'settings',
@@ -62,7 +56,6 @@ const primaryMenuItems = accountId => [
label: 'SETTINGS',
toState: frontendURL(`accounts/${accountId}/settings`),
toStateName: 'settings_home',
- roles: ['administrator', 'agent'],
},
];
diff --git a/app/javascript/dashboard/components/layout/config/sidebarItems/settings.js b/app/javascript/dashboard/components/layout/config/sidebarItems/settings.js
index f450bd7a7..f7d63f6a1 100644
--- a/app/javascript/dashboard/components/layout/config/sidebarItems/settings.js
+++ b/app/javascript/dashboard/components/layout/config/sidebarItems/settings.js
@@ -24,7 +24,6 @@ const settings = accountId => ({
'settings_inbox_list',
'settings_inbox_new',
'settings_inbox_show',
- 'settings_inbox',
'settings_inboxes_add_agents',
'settings_inboxes_page_channel',
'settings_integrations_dashboard_apps',
@@ -46,6 +45,9 @@ const settings = accountId => ({
icon: 'briefcase',
label: 'ACCOUNT_SETTINGS',
hasSubMenu: false,
+ meta: {
+ permissions: ['administrator'],
+ },
toState: frontendURL(`accounts/${accountId}/settings/general`),
toStateName: 'general_settings_index',
},
@@ -53,6 +55,9 @@ const settings = accountId => ({
icon: 'people',
label: 'AGENTS',
hasSubMenu: false,
+ meta: {
+ permissions: ['administrator'],
+ },
toState: frontendURL(`accounts/${accountId}/settings/agents/list`),
toStateName: 'agent_list',
featureFlag: FEATURE_FLAGS.AGENT_MANAGEMENT,
@@ -61,6 +66,9 @@ const settings = accountId => ({
icon: 'people-team',
label: 'TEAMS',
hasSubMenu: false,
+ meta: {
+ permissions: ['administrator'],
+ },
toState: frontendURL(`accounts/${accountId}/settings/teams/list`),
toStateName: 'settings_teams_list',
featureFlag: FEATURE_FLAGS.TEAM_MANAGEMENT,
@@ -69,6 +77,9 @@ const settings = accountId => ({
icon: 'mail-inbox-all',
label: 'INBOXES',
hasSubMenu: false,
+ meta: {
+ permissions: ['administrator'],
+ },
toState: frontendURL(`accounts/${accountId}/settings/inboxes/list`),
toStateName: 'settings_inbox_list',
featureFlag: FEATURE_FLAGS.INBOX_MANAGEMENT,
@@ -77,6 +88,9 @@ const settings = accountId => ({
icon: 'tag',
label: 'LABELS',
hasSubMenu: false,
+ meta: {
+ permissions: ['administrator'],
+ },
toState: frontendURL(`accounts/${accountId}/settings/labels/list`),
toStateName: 'labels_list',
featureFlag: FEATURE_FLAGS.LABELS,
@@ -85,6 +99,9 @@ const settings = accountId => ({
icon: 'code',
label: 'CUSTOM_ATTRIBUTES',
hasSubMenu: false,
+ meta: {
+ permissions: ['administrator'],
+ },
toState: frontendURL(
`accounts/${accountId}/settings/custom-attributes/list`
),
@@ -95,6 +112,9 @@ const settings = accountId => ({
icon: 'automation',
label: 'AUTOMATION',
hasSubMenu: false,
+ meta: {
+ permissions: ['administrator'],
+ },
toState: frontendURL(`accounts/${accountId}/settings/automation/list`),
toStateName: 'automation_list',
featureFlag: FEATURE_FLAGS.AUTOMATIONS,
@@ -103,6 +123,9 @@ const settings = accountId => ({
icon: 'bot',
label: 'AGENT_BOTS',
hasSubMenu: false,
+ meta: {
+ permissions: ['administrator'],
+ },
globalConfigFlag: 'csmlEditorHost',
toState: frontendURL(`accounts/${accountId}/settings/agent-bots`),
toStateName: 'agent_bots',
@@ -112,6 +135,9 @@ const settings = accountId => ({
icon: 'flash-settings',
label: 'MACROS',
hasSubMenu: false,
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
toState: frontendURL(`accounts/${accountId}/settings/macros`),
toStateName: 'macros_wrapper',
featureFlag: FEATURE_FLAGS.MACROS,
@@ -120,6 +146,9 @@ const settings = accountId => ({
icon: 'chat-multiple',
label: 'CANNED_RESPONSES',
hasSubMenu: false,
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
toState: frontendURL(
`accounts/${accountId}/settings/canned-response/list`
),
@@ -130,6 +159,9 @@ const settings = accountId => ({
icon: 'flash-on',
label: 'INTEGRATIONS',
hasSubMenu: false,
+ meta: {
+ permissions: ['administrator'],
+ },
toState: frontendURL(`accounts/${accountId}/settings/integrations`),
toStateName: 'settings_integrations',
featureFlag: FEATURE_FLAGS.INTEGRATIONS,
@@ -138,6 +170,9 @@ const settings = accountId => ({
icon: 'star-emphasis',
label: 'APPLICATIONS',
hasSubMenu: false,
+ meta: {
+ permissions: ['administrator'],
+ },
toState: frontendURL(`accounts/${accountId}/settings/applications`),
toStateName: 'settings_applications',
featureFlag: FEATURE_FLAGS.INTEGRATIONS,
@@ -146,6 +181,9 @@ const settings = accountId => ({
icon: 'key',
label: 'AUDIT_LOGS',
hasSubMenu: false,
+ meta: {
+ permissions: ['administrator'],
+ },
toState: frontendURL(`accounts/${accountId}/settings/audit-log/list`),
toStateName: 'auditlogs_list',
isEnterpriseOnly: true,
@@ -156,6 +194,9 @@ const settings = accountId => ({
icon: 'document-list-clock',
label: 'SLA',
hasSubMenu: false,
+ meta: {
+ permissions: ['administrator'],
+ },
toState: frontendURL(`accounts/${accountId}/settings/sla/list`),
toStateName: 'sla_list',
isEnterpriseOnly: true,
@@ -166,6 +207,9 @@ const settings = accountId => ({
icon: 'credit-card-person',
label: 'BILLING',
hasSubMenu: false,
+ meta: {
+ permissions: ['administrator'],
+ },
toState: frontendURL(`accounts/${accountId}/settings/billing`),
toStateName: 'billing_settings_index',
showOnlyOnCloud: true,
diff --git a/app/javascript/dashboard/components/layout/sidebarComponents/Secondary.vue b/app/javascript/dashboard/components/layout/sidebarComponents/Secondary.vue
index f291d221e..b4cd3ca90 100644
--- a/app/javascript/dashboard/components/layout/sidebarComponents/Secondary.vue
+++ b/app/javascript/dashboard/components/layout/sidebarComponents/Secondary.vue
@@ -29,6 +29,8 @@ import SecondaryNavItem from './SecondaryNavItem.vue';
import AccountContext from './AccountContext.vue';
import { mapGetters } from 'vuex';
import { FEATURE_FLAGS } from '../../../featureFlags';
+import { hasPermissions } from '../../../helper/permissionsHelper';
+import { routesWithPermissions } from '../../../routes';
export default {
components: {
@@ -60,9 +62,9 @@ export default {
type: Object,
default: () => {},
},
- currentRole: {
- type: String,
- default: '',
+ currentUser: {
+ type: Object,
+ default: () => {},
},
isOnChatwootCloud: {
type: Boolean,
@@ -80,16 +82,16 @@ export default {
return this.customViews.filter(view => view.filter_type === 'contact');
},
accessibleMenuItems() {
- if (!this.currentRole) {
- return [];
- }
- const menuItemsFilteredByRole = this.menuConfig.menuItems.filter(
- menuItem =>
- window.roleWiseRoutes[this.currentRole].indexOf(
- menuItem.toStateName
- ) > -1
+ const menuItemsFilteredByPermissions = this.menuConfig.menuItems.filter(
+ menuItem => {
+ const { permissions: userPermissions = [] } = this.currentUser;
+ return hasPermissions(
+ routesWithPermissions[menuItem.toStateName],
+ userPermissions
+ );
+ }
);
- return menuItemsFilteredByRole.filter(item => {
+ return menuItemsFilteredByPermissions.filter(item => {
if (item.showOnlyOnCloud) {
return this.isOnChatwootCloud;
}
diff --git a/app/javascript/dashboard/components/layout/sidebarComponents/SecondaryNavItem.vue b/app/javascript/dashboard/components/layout/sidebarComponents/SecondaryNavItem.vue
index a7009523a..bc3b03646 100644
--- a/app/javascript/dashboard/components/layout/sidebarComponents/SecondaryNavItem.vue
+++ b/app/javascript/dashboard/components/layout/sidebarComponents/SecondaryNavItem.vue
@@ -65,27 +65,29 @@
:show-child-count="showChildCount(child.count)"
:child-item-count="child.count"
/>
-
-
-
- newLinkClick(e, navigate)"
- >
- {{ $t(`SIDEBAR.${menuItem.newLinkTag}`) }}
-
-
-
-
+
+
+
+
+ newLinkClick(e, navigate)"
+ >
+ {{ $t(`SIDEBAR.${menuItem.newLinkTag}`) }}
+
+
+
+
+
@@ -105,9 +107,10 @@ import {
isOnMentionsView,
isOnUnattendedView,
} from '../../../store/modules/conversations/helpers/actionHelpers';
+import Policy from '../../policy.vue';
export default {
- components: { SecondaryChildNavItem },
+ components: { SecondaryChildNavItem, Policy },
mixins: [adminMixin, configMixin],
props: {
menuItem: {
diff --git a/app/javascript/dashboard/components/policy.vue b/app/javascript/dashboard/components/policy.vue
new file mode 100644
index 000000000..f888de5a2
--- /dev/null
+++ b/app/javascript/dashboard/components/policy.vue
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
diff --git a/app/javascript/dashboard/helper/permissionsHelper.js b/app/javascript/dashboard/helper/permissionsHelper.js
new file mode 100644
index 000000000..135238371
--- /dev/null
+++ b/app/javascript/dashboard/helper/permissionsHelper.js
@@ -0,0 +1,34 @@
+export const hasPermissions = (
+ requiredPermissions = [],
+ availablePermissions = []
+) => {
+ return requiredPermissions.some(permission =>
+ availablePermissions.includes(permission)
+ );
+};
+
+const isPermissionsPresentInRoute = route =>
+ route.meta && route.meta.permissions;
+
+export const buildPermissionsFromRouter = (routes = []) =>
+ routes.reduce((acc, route) => {
+ if (route.name) {
+ if (!isPermissionsPresentInRoute(route)) {
+ // eslint-disable-next-line
+ console.error(route);
+ throw new Error(
+ "The route doesn't have the required permissions defined"
+ );
+ }
+ acc[route.name] = route.meta.permissions;
+ }
+
+ if (route.children) {
+ acc = {
+ ...acc,
+ ...buildPermissionsFromRouter(route.children),
+ };
+ }
+
+ return acc;
+ }, {});
diff --git a/app/javascript/dashboard/helper/routeHelpers.js b/app/javascript/dashboard/helper/routeHelpers.js
index 68cf0a627..6c4036dd1 100644
--- a/app/javascript/dashboard/helper/routeHelpers.js
+++ b/app/javascript/dashboard/helper/routeHelpers.js
@@ -1,19 +1,16 @@
+import { hasPermissions } from './permissionsHelper';
+
// eslint-disable-next-line default-param-last
export const getCurrentAccount = ({ accounts } = {}, accountId) => {
return accounts.find(account => account.id === accountId);
};
-// eslint-disable-next-line default-param-last
-export const getUserRole = ({ accounts } = {}, accountId) => {
- const currentAccount = getCurrentAccount({ accounts }, accountId) || {};
- return currentAccount.role || null;
+export const routeIsAccessibleFor = (route, userPermissions = []) => {
+ const { meta: { permissions: routePermissions = [] } = {} } = route;
+ return hasPermissions(routePermissions, userPermissions);
};
-export const routeIsAccessibleFor = (route, role, roleWiseRoutes) => {
- return roleWiseRoutes[role].includes(route);
-};
-
-const validateActiveAccountRoutes = (to, user, roleWiseRoutes) => {
+const validateActiveAccountRoutes = (to, user) => {
// If the current account is active, then check for the route permissions
const accountDashboardURL = `accounts/${to.params.accountId}/dashboard`;
@@ -22,15 +19,13 @@ const validateActiveAccountRoutes = (to, user, roleWiseRoutes) => {
return accountDashboardURL;
}
- const userRole = getUserRole(user, Number(to.params.accountId));
- const isAccessible = routeIsAccessibleFor(to.name, userRole, roleWiseRoutes);
+ const isAccessible = routeIsAccessibleFor(to, user.permissions);
// If the route is not accessible for the user, return to dashboard screen
return isAccessible ? null : accountDashboardURL;
};
-export const validateLoggedInRoutes = (to, user, roleWiseRoutes) => {
+export const validateLoggedInRoutes = (to, user) => {
const currentAccount = getCurrentAccount(user, Number(to.params.accountId));
-
// If current account is missing, either user does not have
// access to the account or the account is deleted, return to login screen
if (!currentAccount) {
@@ -40,7 +35,7 @@ export const validateLoggedInRoutes = (to, user, roleWiseRoutes) => {
const isCurrentAccountActive = currentAccount.status === 'active';
if (isCurrentAccountActive) {
- return validateActiveAccountRoutes(to, user, roleWiseRoutes);
+ return validateActiveAccountRoutes(to, user);
}
// If the current account is not active, then redirect the user to the suspended screen
diff --git a/app/javascript/dashboard/helper/specs/permissionsHelper.spec.js b/app/javascript/dashboard/helper/specs/permissionsHelper.spec.js
new file mode 100644
index 000000000..34f434f7d
--- /dev/null
+++ b/app/javascript/dashboard/helper/specs/permissionsHelper.spec.js
@@ -0,0 +1,84 @@
+import {
+ buildPermissionsFromRouter,
+ hasPermissions,
+} from '../permissionsHelper';
+
+describe('hasPermissions', () => {
+ it('returns true if permission is present', () => {
+ expect(
+ hasPermissions(['contact_manage'], ['team_manage', 'contact_manage'])
+ ).toBe(true);
+ });
+
+ it('returns true if permission is not present', () => {
+ expect(
+ hasPermissions(['contact_manage'], ['team_manage', 'user_manage'])
+ ).toBe(false);
+ expect(hasPermissions()).toBe(false);
+ expect(hasPermissions([])).toBe(false);
+ });
+});
+
+describe('buildPermissionsFromRouter', () => {
+ it('returns a valid object when routes have permissions defined', () => {
+ expect(
+ buildPermissionsFromRouter([
+ {
+ path: 'agent',
+ name: 'agent_list',
+ meta: { permissions: ['agent_admin'] },
+ },
+ {
+ path: 'inbox',
+ children: [
+ {
+ path: '',
+ name: 'inbox_list',
+ meta: { permissions: ['inbox_admin'] },
+ },
+ ],
+ },
+ {
+ path: 'conversations',
+ children: [
+ {
+ path: '',
+ children: [
+ {
+ path: 'attachments',
+ name: 'attachments_list',
+ meta: { permissions: ['conversation_admin'] },
+ },
+ ],
+ },
+ ],
+ },
+ ])
+ ).toEqual({
+ agent_list: ['agent_admin'],
+ inbox_list: ['inbox_admin'],
+ attachments_list: ['conversation_admin'],
+ });
+ });
+
+ it('throws an error if a named routed does not have permissions defined', () => {
+ expect(() => {
+ buildPermissionsFromRouter([
+ {
+ path: 'agent',
+ name: 'agent_list',
+ },
+ ]);
+ }).toThrow("The route doesn't have the required permissions defined");
+
+ expect(() => {
+ buildPermissionsFromRouter([
+ {
+ path: 'agent',
+ name: 'agent_list',
+ meta: {},
+ },
+ ]);
+ }).toThrow("The route doesn't have the required permissions defined");
+ });
+});
diff --git a/app/javascript/dashboard/helper/specs/routeHelpers.spec.js b/app/javascript/dashboard/helper/specs/routeHelpers.spec.js
index 1e100a678..5aa9c4ee2 100644
--- a/app/javascript/dashboard/helper/specs/routeHelpers.spec.js
+++ b/app/javascript/dashboard/helper/specs/routeHelpers.spec.js
@@ -1,7 +1,6 @@
import {
getConversationDashboardRoute,
getCurrentAccount,
- getUserRole,
isAConversationRoute,
routeIsAccessibleFor,
validateLoggedInRoutes,
@@ -15,24 +14,11 @@ describe('#getCurrentAccount', () => {
});
});
-describe('#getUserRole', () => {
- it('should return the current role', () => {
- expect(
- getUserRole({ accounts: [{ id: 1, role: 'administrator' }] }, 1)
- ).toEqual('administrator');
- expect(getUserRole({ accounts: [] }, 1)).toEqual(null);
- });
-});
-
describe('#routeIsAccessibleFor', () => {
it('should return the correct access', () => {
- const roleWiseRoutes = { agent: ['conversations'], admin: ['billing'] };
- expect(routeIsAccessibleFor('billing', 'agent', roleWiseRoutes)).toEqual(
- false
- );
- expect(routeIsAccessibleFor('billing', 'admin', roleWiseRoutes)).toEqual(
- true
- );
+ let route = { meta: { permissions: ['administrator'] } };
+ expect(routeIsAccessibleFor(route, ['agent'])).toEqual(false);
+ expect(routeIsAccessibleFor(route, ['administrator'])).toEqual(true);
});
});
@@ -40,11 +26,7 @@ describe('#validateLoggedInRoutes', () => {
describe('when account access is missing', () => {
it('should return the login route', () => {
expect(
- validateLoggedInRoutes(
- { params: { accountId: 1 } },
- { accounts: [] },
- {}
- )
+ validateLoggedInRoutes({ params: { accountId: 1 } }, { accounts: [] })
).toEqual(`app/login`);
});
});
@@ -53,9 +35,12 @@ describe('#validateLoggedInRoutes', () => {
it('return suspended route', () => {
expect(
validateLoggedInRoutes(
- { name: 'conversations', params: { accountId: 1 } },
- { accounts: [{ id: 1, role: 'agent', status: 'suspended' }] },
- { agent: ['conversations'] }
+ {
+ name: 'conversations',
+ params: { accountId: 1 },
+ meta: { permissions: ['agent'] },
+ },
+ { accounts: [{ id: 1, role: 'agent', status: 'suspended' }] }
)
).toEqual(`accounts/1/suspended`);
});
@@ -65,9 +50,22 @@ describe('#validateLoggedInRoutes', () => {
it('returns null (no action required)', () => {
expect(
validateLoggedInRoutes(
- { name: 'conversations', params: { accountId: 1 } },
- { accounts: [{ id: 1, role: 'agent', status: 'active' }] },
- { agent: ['conversations'] }
+ {
+ name: 'conversations',
+ params: { accountId: 1 },
+ meta: { permissions: ['agent'] },
+ },
+ {
+ permissions: ['agent'],
+ accounts: [
+ {
+ id: 1,
+ role: 'agent',
+ permissions: ['agent'],
+ status: 'active',
+ },
+ ],
+ }
)
).toEqual(null);
});
@@ -76,9 +74,12 @@ describe('#validateLoggedInRoutes', () => {
it('returns dashboard url', () => {
expect(
validateLoggedInRoutes(
- { name: 'conversations', params: { accountId: 1 } },
- { accounts: [{ id: 1, role: 'agent', status: 'active' }] },
- { admin: ['conversations'], agent: [] }
+ {
+ name: 'billing',
+ params: { accountId: 1 },
+ meta: { permissions: ['administrator'] },
+ },
+ { accounts: [{ id: 1, role: 'agent', status: 'active' }] }
)
).toEqual(`accounts/1/dashboard`);
});
@@ -88,8 +89,7 @@ describe('#validateLoggedInRoutes', () => {
expect(
validateLoggedInRoutes(
{ name: 'account_suspended', params: { accountId: 1 } },
- { accounts: [{ id: 1, role: 'agent', status: 'active' }] },
- { agent: ['account_suspended'] }
+ { accounts: [{ id: 1, role: 'agent', status: 'active' }] }
)
).toEqual(`accounts/1/dashboard`);
});
diff --git a/app/javascript/dashboard/modules/search/search.routes.js b/app/javascript/dashboard/modules/search/search.routes.js
index 320f64a44..d2d7b19c4 100644
--- a/app/javascript/dashboard/modules/search/search.routes.js
+++ b/app/javascript/dashboard/modules/search/search.routes.js
@@ -7,7 +7,9 @@ export const routes = [
{
path: frontendURL('accounts/:accountId/search'),
name: 'search',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
component: SearchView,
},
];
diff --git a/app/javascript/dashboard/routes/dashboard/contacts/routes.js b/app/javascript/dashboard/routes/dashboard/contacts/routes.js
index 10a560740..a07ca6bf3 100644
--- a/app/javascript/dashboard/routes/dashboard/contacts/routes.js
+++ b/app/javascript/dashboard/routes/dashboard/contacts/routes.js
@@ -7,13 +7,17 @@ export const routes = [
{
path: frontendURL('accounts/:accountId/contacts'),
name: 'contacts_dashboard',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
component: ContactsView,
},
{
path: frontendURL('accounts/:accountId/contacts/custom_view/:id'),
name: 'contacts_segments_dashboard',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
component: ContactsView,
props: route => {
return { segmentsId: route.params.id };
@@ -22,7 +26,9 @@ export const routes = [
{
path: frontendURL('accounts/:accountId/labels/:label/contacts'),
name: 'contacts_labels_dashboard',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
component: ContactsView,
props: route => {
return { label: route.params.label };
@@ -31,7 +37,9 @@ export const routes = [
{
path: frontendURL('accounts/:accountId/contacts/:contactId'),
name: 'contact_profile_dashboard',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
component: ContactManageView,
props: route => {
return { contactId: route.params.contactId };
diff --git a/app/javascript/dashboard/routes/dashboard/conversation/conversation.routes.js b/app/javascript/dashboard/routes/dashboard/conversation/conversation.routes.js
index 14487682e..7a81e2f4e 100644
--- a/app/javascript/dashboard/routes/dashboard/conversation/conversation.routes.js
+++ b/app/javascript/dashboard/routes/dashboard/conversation/conversation.routes.js
@@ -7,7 +7,9 @@ export default {
{
path: frontendURL('accounts/:accountId/dashboard'),
name: 'home',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
component: ConversationView,
props: () => {
return { inboxId: 0 };
@@ -16,7 +18,9 @@ export default {
{
path: frontendURL('accounts/:accountId/conversations/:conversation_id'),
name: 'inbox_conversation',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
component: ConversationView,
props: route => {
return { inboxId: 0, conversationId: route.params.conversation_id };
@@ -25,7 +29,9 @@ export default {
{
path: frontendURL('accounts/:accountId/inbox/:inbox_id'),
name: 'inbox_dashboard',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
component: ConversationView,
props: route => {
return { inboxId: route.params.inbox_id };
@@ -36,7 +42,9 @@ export default {
'accounts/:accountId/inbox/:inbox_id/conversations/:conversation_id'
),
name: 'conversation_through_inbox',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
component: ConversationView,
props: route => {
return {
@@ -48,7 +56,9 @@ export default {
{
path: frontendURL('accounts/:accountId/label/:label'),
name: 'label_conversations',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
component: ConversationView,
props: route => ({ label: route.params.label }),
},
@@ -57,7 +67,9 @@ export default {
'accounts/:accountId/label/:label/conversations/:conversation_id'
),
name: 'conversations_through_label',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
component: ConversationView,
props: route => ({
conversationId: route.params.conversation_id,
@@ -67,7 +79,9 @@ export default {
{
path: frontendURL('accounts/:accountId/team/:teamId'),
name: 'team_conversations',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
component: ConversationView,
props: route => ({ teamId: route.params.teamId }),
},
@@ -76,7 +90,9 @@ export default {
'accounts/:accountId/team/:teamId/conversations/:conversationId'
),
name: 'conversations_through_team',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
component: ConversationView,
props: route => ({
conversationId: route.params.conversationId,
@@ -86,7 +102,9 @@ export default {
{
path: frontendURL('accounts/:accountId/custom_view/:id'),
name: 'folder_conversations',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
component: ConversationView,
props: route => ({ foldersId: route.params.id }),
},
@@ -95,7 +113,9 @@ export default {
'accounts/:accountId/custom_view/:id/conversations/:conversation_id'
),
name: 'conversations_through_folders',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
component: ConversationView,
props: route => ({
conversationId: route.params.conversation_id,
@@ -105,7 +125,9 @@ export default {
{
path: frontendURL('accounts/:accountId/mentions/conversations'),
name: 'conversation_mentions',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
component: ConversationView,
props: () => ({ conversationType: 'mention' }),
},
@@ -114,7 +136,9 @@ export default {
'accounts/:accountId/mentions/conversations/:conversationId'
),
name: 'conversation_through_mentions',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
component: ConversationView,
props: route => ({
conversationId: route.params.conversationId,
@@ -124,7 +148,9 @@ export default {
{
path: frontendURL('accounts/:accountId/unattended/conversations'),
name: 'conversation_unattended',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
component: ConversationView,
props: () => ({ conversationType: 'unattended' }),
},
@@ -133,7 +159,9 @@ export default {
'accounts/:accountId/unattended/conversations/:conversationId'
),
name: 'conversation_through_unattended',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
component: ConversationView,
props: route => ({
conversationId: route.params.conversationId,
@@ -143,7 +171,9 @@ export default {
{
path: frontendURL('accounts/:accountId/participating/conversations'),
name: 'conversation_participating',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
component: ConversationView,
props: () => ({ conversationType: 'participating' }),
},
@@ -152,7 +182,9 @@ export default {
'accounts/:accountId/participating/conversations/:conversationId'
),
name: 'conversation_through_participating',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
component: ConversationView,
props: route => ({
conversationId: route.params.conversationId,
diff --git a/app/javascript/dashboard/routes/dashboard/dashboard.routes.js b/app/javascript/dashboard/routes/dashboard/dashboard.routes.js
index 9e18ca42c..b02f29342 100644
--- a/app/javascript/dashboard/routes/dashboard/dashboard.routes.js
+++ b/app/javascript/dashboard/routes/dashboard/dashboard.routes.js
@@ -28,7 +28,9 @@ export default {
{
path: frontendURL('accounts/:accountId/suspended'),
name: 'account_suspended',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
component: Suspended,
},
],
diff --git a/app/javascript/dashboard/routes/dashboard/helpcenter/helpcenter.routes.js b/app/javascript/dashboard/routes/dashboard/helpcenter/helpcenter.routes.js
index a165b0277..0326534f3 100644
--- a/app/javascript/dashboard/routes/dashboard/helpcenter/helpcenter.routes.js
+++ b/app/javascript/dashboard/routes/dashboard/helpcenter/helpcenter.routes.js
@@ -30,13 +30,17 @@ const portalRoutes = [
{
path: getPortalRoute(''),
name: 'default_portal_articles',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator'],
+ },
component: DefaultPortalArticles,
},
{
path: getPortalRoute('all'),
name: 'list_all_portals',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
component: ListAllPortals,
},
{
@@ -47,55 +51,73 @@ const portalRoutes = [
path: '',
name: 'new_portal_information',
component: PortalDetails,
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
},
{
path: ':portalSlug/customization',
name: 'portal_customization',
component: PortalCustomization,
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
},
{
path: ':portalSlug/finish',
name: 'portal_finish',
component: PortalSettingsFinish,
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
},
],
},
{
path: getPortalRoute(':portalSlug'),
name: 'portalSlug',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
component: ShowPortal,
},
{
path: getPortalRoute(':portalSlug/edit'),
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
component: EditPortal,
children: [
{
path: '',
name: 'edit_portal_information',
component: EditPortalBasic,
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
},
{
path: 'customizations',
name: 'edit_portal_customization',
component: EditPortalCustomization,
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
},
{
path: 'locales',
name: 'edit_portal_locales',
component: EditPortalLocales,
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
},
{
path: 'categories',
name: 'list_all_locale_categories',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
component: ListAllCategories,
},
],
@@ -106,39 +128,51 @@ const articleRoutes = [
{
path: getPortalRoute(':portalSlug/:locale/articles'),
name: 'list_all_locale_articles',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
component: ListAllArticles,
},
{
path: getPortalRoute(':portalSlug/:locale/articles/new'),
name: 'new_article',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
component: NewArticle,
},
{
path: getPortalRoute(':portalSlug/:locale/articles/mine'),
name: 'list_mine_articles',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
component: ListAllArticles,
},
{
path: getPortalRoute(':portalSlug/:locale/articles/archived'),
name: 'list_archived_articles',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
component: ListAllArticles,
},
{
path: getPortalRoute(':portalSlug/:locale/articles/draft'),
name: 'list_draft_articles',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
component: ListAllArticles,
},
{
path: getPortalRoute(':portalSlug/:locale/articles/:articleSlug'),
name: 'edit_article',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
component: EditArticle,
},
];
@@ -147,19 +181,25 @@ const categoryRoutes = [
{
path: getPortalRoute(':portalSlug/:locale/categories'),
name: 'all_locale_categories',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
component: ListAllCategories,
},
{
path: getPortalRoute(':portalSlug/:locale/categories/new'),
name: 'new_category_in_locale',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
component: NewCategory,
},
{
path: getPortalRoute(':portalSlug/:locale/categories/:categorySlug'),
name: 'show_category',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
component: ListAllArticles,
},
{
@@ -167,13 +207,17 @@ const categoryRoutes = [
':portalSlug/:locale/categories/:categorySlug/articles'
),
name: 'show_category_articles',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
component: ListCategoryArticles,
},
{
path: getPortalRoute(':portalSlug/:locale/categories/:categorySlug'),
name: 'edit_category',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
component: EditCategory,
},
];
diff --git a/app/javascript/dashboard/routes/dashboard/inbox/routes.js b/app/javascript/dashboard/routes/dashboard/inbox/routes.js
index 9c26fa64e..729fee76d 100644
--- a/app/javascript/dashboard/routes/dashboard/inbox/routes.js
+++ b/app/javascript/dashboard/routes/dashboard/inbox/routes.js
@@ -12,13 +12,17 @@ export const routes = [
path: '',
name: 'inbox_view',
component: InboxEmptyStateView,
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
},
{
path: ':notification_id',
name: 'inbox_view_conversation',
component: InboxDetailView,
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
},
],
},
diff --git a/app/javascript/dashboard/routes/dashboard/notifications/routes.js b/app/javascript/dashboard/routes/dashboard/notifications/routes.js
index 38812fc92..e3d125333 100644
--- a/app/javascript/dashboard/routes/dashboard/notifications/routes.js
+++ b/app/javascript/dashboard/routes/dashboard/notifications/routes.js
@@ -18,7 +18,9 @@ export const routes = [
path: '',
name: 'notifications_index',
component: NotificationsView,
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
},
],
},
diff --git a/app/javascript/dashboard/routes/dashboard/settings/account/account.routes.js b/app/javascript/dashboard/routes/dashboard/settings/account/account.routes.js
index 0acfd5bd5..2742621e9 100644
--- a/app/javascript/dashboard/routes/dashboard/settings/account/account.routes.js
+++ b/app/javascript/dashboard/routes/dashboard/settings/account/account.routes.js
@@ -6,7 +6,9 @@ export default {
routes: [
{
path: frontendURL('accounts/:accountId/settings/general'),
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
component: SettingsContent,
props: {
headerTitle: 'GENERAL_SETTINGS.TITLE',
@@ -18,7 +20,9 @@ export default {
path: '',
name: 'general_settings_index',
component: Index,
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
},
],
},
diff --git a/app/javascript/dashboard/routes/dashboard/settings/agentBots/agentBot.routes.js b/app/javascript/dashboard/routes/dashboard/settings/agentBots/agentBot.routes.js
index 382594c73..55210397f 100644
--- a/app/javascript/dashboard/routes/dashboard/settings/agentBots/agentBot.routes.js
+++ b/app/javascript/dashboard/routes/dashboard/settings/agentBots/agentBot.routes.js
@@ -8,7 +8,9 @@ export default {
routes: [
{
path: frontendURL('accounts/:accountId/settings/agent-bots'),
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
component: SettingsContent,
props: {
headerTitle: 'AGENT_BOTS.HEADER',
@@ -20,19 +22,25 @@ export default {
path: '',
name: 'agent_bots',
component: Bot,
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
},
{
path: 'csml/new',
name: 'agent_bots_csml_new',
component: CsmlNewBot,
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
},
{
path: 'csml/:botId',
name: 'agent_bots_csml_edit',
component: CsmlEditBot,
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
},
],
},
diff --git a/app/javascript/dashboard/routes/dashboard/settings/agents/agent.routes.js b/app/javascript/dashboard/routes/dashboard/settings/agents/agent.routes.js
index cd23432ff..854450c5d 100644
--- a/app/javascript/dashboard/routes/dashboard/settings/agents/agent.routes.js
+++ b/app/javascript/dashboard/routes/dashboard/settings/agents/agent.routes.js
@@ -15,14 +15,15 @@ export default {
children: [
{
path: '',
- name: 'agents_wrapper',
redirect: 'list',
},
{
path: 'list',
name: 'agent_list',
component: AgentHome,
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
},
],
},
diff --git a/app/javascript/dashboard/routes/dashboard/settings/attributes/attributes.routes.js b/app/javascript/dashboard/routes/dashboard/settings/attributes/attributes.routes.js
index 72d79a9de..93c4f8eda 100644
--- a/app/javascript/dashboard/routes/dashboard/settings/attributes/attributes.routes.js
+++ b/app/javascript/dashboard/routes/dashboard/settings/attributes/attributes.routes.js
@@ -15,14 +15,15 @@ export default {
children: [
{
path: '',
- name: 'attributes_wrapper',
redirect: 'list',
},
{
path: 'list',
name: 'attributes_list',
component: AttributesHome,
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
},
],
},
diff --git a/app/javascript/dashboard/routes/dashboard/settings/auditlogs/audit.routes.js b/app/javascript/dashboard/routes/dashboard/settings/auditlogs/audit.routes.js
index 00c1fda74..acf061288 100644
--- a/app/javascript/dashboard/routes/dashboard/settings/auditlogs/audit.routes.js
+++ b/app/javascript/dashboard/routes/dashboard/settings/auditlogs/audit.routes.js
@@ -16,13 +16,14 @@ export default {
children: [
{
path: '',
- name: 'auditlogs_wrapper',
redirect: 'list',
},
{
path: 'list',
name: 'auditlogs_list',
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
component: AuditLogsHome,
},
],
diff --git a/app/javascript/dashboard/routes/dashboard/settings/automation/automation.routes.js b/app/javascript/dashboard/routes/dashboard/settings/automation/automation.routes.js
index 3a5d6c887..14b03a45a 100644
--- a/app/javascript/dashboard/routes/dashboard/settings/automation/automation.routes.js
+++ b/app/javascript/dashboard/routes/dashboard/settings/automation/automation.routes.js
@@ -15,14 +15,15 @@ export default {
children: [
{
path: '',
- name: 'automation_wrapper',
redirect: 'list',
},
{
path: 'list',
name: 'automation_list',
component: Automation,
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
},
],
},
diff --git a/app/javascript/dashboard/routes/dashboard/settings/billing/billing.routes.js b/app/javascript/dashboard/routes/dashboard/settings/billing/billing.routes.js
index 7a37f320a..f1042e81a 100644
--- a/app/javascript/dashboard/routes/dashboard/settings/billing/billing.routes.js
+++ b/app/javascript/dashboard/routes/dashboard/settings/billing/billing.routes.js
@@ -6,7 +6,9 @@ export default {
routes: [
{
path: frontendURL('accounts/:accountId/settings/billing'),
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
component: SettingsContent,
props: {
headerTitle: 'BILLING_SETTINGS.TITLE',
@@ -18,7 +20,9 @@ export default {
path: '',
name: 'billing_settings_index',
component: Index,
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
},
],
},
diff --git a/app/javascript/dashboard/routes/dashboard/settings/campaigns/campaigns.routes.js b/app/javascript/dashboard/routes/dashboard/settings/campaigns/campaigns.routes.js
index 1ac007ed6..5c8581981 100644
--- a/app/javascript/dashboard/routes/dashboard/settings/campaigns/campaigns.routes.js
+++ b/app/javascript/dashboard/routes/dashboard/settings/campaigns/campaigns.routes.js
@@ -19,7 +19,9 @@ export default {
{
path: 'ongoing',
name: 'ongoing_campaigns',
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
component: Index,
},
],
@@ -35,7 +37,9 @@ export default {
{
path: 'one_off',
name: 'one_off',
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
component: Index,
},
],
diff --git a/app/javascript/dashboard/routes/dashboard/settings/canned/canned.routes.js b/app/javascript/dashboard/routes/dashboard/settings/canned/canned.routes.js
index 73b370e2a..236801c8c 100644
--- a/app/javascript/dashboard/routes/dashboard/settings/canned/canned.routes.js
+++ b/app/javascript/dashboard/routes/dashboard/settings/canned/canned.routes.js
@@ -16,13 +16,14 @@ export default {
children: [
{
path: '',
- name: 'canned_wrapper',
redirect: 'list',
},
{
path: 'list',
name: 'canned_list',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
component: CannedHome,
},
],
diff --git a/app/javascript/dashboard/routes/dashboard/settings/inbox/inbox.routes.js b/app/javascript/dashboard/routes/dashboard/settings/inbox/inbox.routes.js
index 4e4c14c00..3866b96bd 100644
--- a/app/javascript/dashboard/routes/dashboard/settings/inbox/inbox.routes.js
+++ b/app/javascript/dashboard/routes/dashboard/settings/inbox/inbox.routes.js
@@ -28,14 +28,15 @@ export default {
children: [
{
path: '',
- name: 'settings_inbox',
redirect: 'list',
},
{
path: 'list',
name: 'settings_inbox_list',
component: InboxHome,
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
},
{
path: 'new',
@@ -45,19 +46,25 @@ export default {
path: '',
name: 'settings_inbox_new',
component: ChannelList,
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
},
{
path: ':inbox_id/finish',
name: 'settings_inbox_finish',
component: FinishSetup,
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
},
{
path: ':sub_page',
name: 'settings_inboxes_page_channel',
component: channelFactory.create(),
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
props: route => {
return { channel_name: route.params.sub_page };
},
@@ -65,7 +72,9 @@ export default {
{
path: ':inbox_id/agents',
name: 'settings_inboxes_add_agents',
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
component: AddAgents,
},
],
@@ -74,7 +83,9 @@ export default {
path: ':inboxId',
name: 'settings_inbox_show',
component: Settings,
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
},
],
},
diff --git a/app/javascript/dashboard/routes/dashboard/settings/integrationapps/integrations.routes.js b/app/javascript/dashboard/routes/dashboard/settings/integrationapps/integrations.routes.js
index a0f8477b2..d3074f62d 100644
--- a/app/javascript/dashboard/routes/dashboard/settings/integrationapps/integrations.routes.js
+++ b/app/javascript/dashboard/routes/dashboard/settings/integrationapps/integrations.routes.js
@@ -26,13 +26,17 @@ export default {
path: '',
name: 'settings_applications',
component: Index,
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
},
{
path: ':integration_id',
name: 'settings_applications_integration',
component: IntegrationHooks,
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
props: route => ({
integrationId: route.params.integration_id,
}),
diff --git a/app/javascript/dashboard/routes/dashboard/settings/integrations/integrations.routes.js b/app/javascript/dashboard/routes/dashboard/settings/integrations/integrations.routes.js
index 542cf591e..bdebc0329 100644
--- a/app/javascript/dashboard/routes/dashboard/settings/integrations/integrations.routes.js
+++ b/app/javascript/dashboard/routes/dashboard/settings/integrations/integrations.routes.js
@@ -30,32 +30,42 @@ export default {
path: '',
name: 'settings_integrations',
component: Index,
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
},
{
path: 'webhook',
component: Webhook,
name: 'settings_integrations_webhook',
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
},
{
path: 'dashboard-apps',
component: DashboardApps,
name: 'settings_integrations_dashboard_apps',
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
},
{
path: 'slack',
name: 'settings_integrations_slack',
component: Slack,
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
props: route => ({ code: route.query.code }),
},
{
path: ':integration_id',
name: 'settings_integrations_integration',
component: ShowIntegration,
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
props: route => {
return {
integrationId: route.params.integration_id,
diff --git a/app/javascript/dashboard/routes/dashboard/settings/labels/labels.routes.js b/app/javascript/dashboard/routes/dashboard/settings/labels/labels.routes.js
index 4fc514da6..088c565d0 100644
--- a/app/javascript/dashboard/routes/dashboard/settings/labels/labels.routes.js
+++ b/app/javascript/dashboard/routes/dashboard/settings/labels/labels.routes.js
@@ -17,13 +17,17 @@ export default {
{
path: '',
name: 'labels_wrapper',
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
redirect: 'list',
},
{
path: 'list',
name: 'labels_list',
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
component: Index,
},
],
diff --git a/app/javascript/dashboard/routes/dashboard/settings/macros/macros.routes.js b/app/javascript/dashboard/routes/dashboard/settings/macros/macros.routes.js
index 58a26819f..06d0014b9 100644
--- a/app/javascript/dashboard/routes/dashboard/settings/macros/macros.routes.js
+++ b/app/javascript/dashboard/routes/dashboard/settings/macros/macros.routes.js
@@ -23,19 +23,25 @@ export default {
path: '',
name: 'macros_wrapper',
component: Macros,
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
},
{
path: 'new',
name: 'macros_new',
component: MacroEditor,
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
},
{
path: ':macroId/edit',
name: 'macros_edit',
component: MacroEditor,
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
},
],
},
diff --git a/app/javascript/dashboard/routes/dashboard/settings/profile/profile.routes.js b/app/javascript/dashboard/routes/dashboard/settings/profile/profile.routes.js
index 357c20e85..31f386e37 100644
--- a/app/javascript/dashboard/routes/dashboard/settings/profile/profile.routes.js
+++ b/app/javascript/dashboard/routes/dashboard/settings/profile/profile.routes.js
@@ -8,14 +8,18 @@ export default {
{
path: frontendURL('accounts/:accountId/profile'),
name: 'profile_settings',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
component: SettingsContent,
children: [
{
path: 'settings',
name: 'profile_settings_index',
component: Index,
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
},
],
},
diff --git a/app/javascript/dashboard/routes/dashboard/settings/reports/reports.routes.js b/app/javascript/dashboard/routes/dashboard/settings/reports/reports.routes.js
index 3792567da..eaca0e76d 100644
--- a/app/javascript/dashboard/routes/dashboard/settings/reports/reports.routes.js
+++ b/app/javascript/dashboard/routes/dashboard/settings/reports/reports.routes.js
@@ -29,7 +29,9 @@ export default {
{
path: 'overview',
name: 'account_overview_reports',
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
component: LiveReports,
},
],
@@ -46,7 +48,9 @@ export default {
{
path: 'conversation',
name: 'conversation_reports',
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
component: Index,
},
],
@@ -63,7 +67,9 @@ export default {
{
path: 'csat',
name: 'csat_reports',
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
component: CsatResponses,
},
],
@@ -80,7 +86,9 @@ export default {
{
path: 'bot',
name: 'bot_reports',
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
component: BotReports,
},
],
@@ -97,7 +105,9 @@ export default {
{
path: 'agent',
name: 'agent_reports',
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
component: AgentReports,
},
],
@@ -114,7 +124,9 @@ export default {
{
path: 'label',
name: 'label_reports',
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
component: LabelReports,
},
],
@@ -131,7 +143,9 @@ export default {
{
path: 'inboxes',
name: 'inbox_reports',
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
component: InboxReports,
},
],
@@ -147,7 +161,9 @@ export default {
{
path: 'teams',
name: 'team_reports',
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
component: TeamReports,
},
],
@@ -164,7 +180,9 @@ export default {
{
path: 'sla',
name: 'sla_reports',
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
component: SLAReports,
},
],
diff --git a/app/javascript/dashboard/routes/dashboard/settings/settings.routes.js b/app/javascript/dashboard/routes/dashboard/settings/settings.routes.js
index dd5291fe8..2829ed1d9 100644
--- a/app/javascript/dashboard/routes/dashboard/settings/settings.routes.js
+++ b/app/javascript/dashboard/routes/dashboard/settings/settings.routes.js
@@ -24,7 +24,9 @@ export default {
{
path: frontendURL('accounts/:accountId/settings'),
name: 'settings_home',
- roles: ['administrator', 'agent'],
+ meta: {
+ permissions: ['administrator', 'agent'],
+ },
redirect: () => {
if (store.getters.getCurrentRole === 'administrator') {
return frontendURL('accounts/:accountId/settings/general');
diff --git a/app/javascript/dashboard/routes/dashboard/settings/sla/sla.routes.js b/app/javascript/dashboard/routes/dashboard/settings/sla/sla.routes.js
index a9c68470a..762d85d58 100644
--- a/app/javascript/dashboard/routes/dashboard/settings/sla/sla.routes.js
+++ b/app/javascript/dashboard/routes/dashboard/settings/sla/sla.routes.js
@@ -13,13 +13,17 @@ export default {
{
path: '',
name: 'sla_wrapper',
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
redirect: 'list',
},
{
path: 'list',
name: 'sla_list',
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
component: Index,
},
],
diff --git a/app/javascript/dashboard/routes/dashboard/settings/teams/teams.routes.js b/app/javascript/dashboard/routes/dashboard/settings/teams/teams.routes.js
index 4228e72e7..c968351f4 100644
--- a/app/javascript/dashboard/routes/dashboard/settings/teams/teams.routes.js
+++ b/app/javascript/dashboard/routes/dashboard/settings/teams/teams.routes.js
@@ -29,14 +29,15 @@ export default {
children: [
{
path: '',
- name: 'settings_teams',
redirect: 'list',
},
{
path: 'list',
name: 'settings_teams_list',
component: TeamsHome,
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
},
{
path: 'new',
@@ -46,18 +47,24 @@ export default {
path: '',
name: 'settings_teams_new',
component: CreateTeam,
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
},
{
path: ':teamId/finish',
name: 'settings_teams_finish',
component: FinishSetup,
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
},
{
path: ':teamId/agents',
name: 'settings_teams_add_agents',
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
component: AddAgents,
},
],
@@ -70,18 +77,24 @@ export default {
path: '',
name: 'settings_teams_edit',
component: EditTeam,
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
},
{
path: 'agents',
name: 'settings_teams_edit_members',
component: EditAgents,
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
},
{
path: 'finish',
name: 'settings_teams_edit_finish',
- roles: ['administrator'],
+ meta: {
+ permissions: ['administrator'],
+ },
component: FinishSetup,
},
],
diff --git a/app/javascript/dashboard/routes/index.js b/app/javascript/dashboard/routes/index.js
index e2245e20f..70d870700 100644
--- a/app/javascript/dashboard/routes/index.js
+++ b/app/javascript/dashboard/routes/index.js
@@ -5,33 +5,12 @@ import dashboard from './dashboard/dashboard.routes';
import store from '../store';
import { validateLoggedInRoutes } from '../helper/routeHelpers';
import AnalyticsHelper from '../helper/AnalyticsHelper';
+import { buildPermissionsFromRouter } from '../helper/permissionsHelper';
const routes = [...dashboard.routes];
-window.roleWiseRoutes = {
- agent: [],
- administrator: [],
-};
-
-// generateRoleWiseRoute - updates window object with agent/admin route
-const generateRoleWiseRoute = route => {
- route.forEach(element => {
- if (element.children) {
- generateRoleWiseRoute(element.children);
- }
- if (element.roles) {
- element.roles.forEach(roleEl => {
- window.roleWiseRoutes[roleEl].push(element.name);
- });
- }
- });
-};
-// Create a object of routes
-// accessible by each role.
-// returns an object with roles as keys and routeArr as values
-generateRoleWiseRoute(routes);
-
export const router = new VueRouter({ mode: 'history', routes });
+export const routesWithPermissions = buildPermissionsFromRouter(routes);
export const validateAuthenticateRoutePermission = (to, next, { getters }) => {
const { isLoggedIn, getCurrentUser: user } = getters;
@@ -45,11 +24,7 @@ export const validateAuthenticateRoutePermission = (to, next, { getters }) => {
return next(frontendURL(`accounts/${user.account_id}/dashboard`));
}
- const nextRoute = validateLoggedInRoutes(
- to,
- getters.getCurrentUser,
- window.roleWiseRoutes
- );
+ const nextRoute = validateLoggedInRoutes(to, getters.getCurrentUser);
return nextRoute ? next(frontendURL(nextRoute)) : next();
};
From aaf47b4c1fc20e787cd088b4bd2efc7fb092efcb Mon Sep 17 00:00:00 2001
From: Sojan Jose
Date: Wed, 3 Jul 2024 15:48:57 -0700
Subject: [PATCH 05/22] chore: [Snyk] Security upgrade sidekiq from 7.2.4 to
7.3.0 (#9710)
Upgrade gems to mitigate vulnerabilities.
Co-authored-by: snyk-bot
---
Gemfile | 2 +-
Gemfile.lock | 8 +++++---
2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/Gemfile b/Gemfile
index 5e1e5917f..ad66c46c6 100644
--- a/Gemfile
+++ b/Gemfile
@@ -116,7 +116,7 @@ gem 'sentry-ruby', require: false
gem 'sentry-sidekiq', '>= 5.18.0', require: false
##-- background job processing --##
-gem 'sidekiq', '>= 7.2.4'
+gem 'sidekiq', '>= 7.3.0'
# We want cron jobs
gem 'sidekiq-cron', '>= 1.12.0'
diff --git a/Gemfile.lock b/Gemfile.lock
index 04a8fb534..54226c13a 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -434,6 +434,7 @@ GEM
llhttp-ffi (0.4.0)
ffi-compiler (~> 1.0)
rake (~> 13.0)
+ logger (1.6.0)
lograge (0.14.0)
actionpack (>= 4)
activesupport (>= 4)
@@ -715,11 +716,12 @@ GEM
sexp_processor (4.17.0)
shoulda-matchers (5.3.0)
activesupport (>= 5.2.0)
- sidekiq (7.2.4)
+ sidekiq (7.3.0)
concurrent-ruby (< 2)
connection_pool (>= 2.3.0)
+ logger
rack (>= 2.2.4)
- redis-client (>= 0.19.0)
+ redis-client (>= 0.22.2)
sidekiq-cron (1.12.0)
fugit (~> 1.8)
globalid (>= 1.0.1)
@@ -935,7 +937,7 @@ DEPENDENCIES
sentry-ruby
sentry-sidekiq (>= 5.18.0)
shoulda-matchers
- sidekiq (>= 7.2.4)
+ sidekiq (>= 7.3.0)
sidekiq-cron (>= 1.12.0)
simplecov (= 0.17.1)
slack-ruby-client (~> 2.2.0)
From 6ae606c981ffdbf5f711de28fb7e587fe5d0da20 Mon Sep 17 00:00:00 2001
From: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
Date: Thu, 4 Jul 2024 13:13:03 +0530
Subject: [PATCH 06/22] fix: Custom snooze is not working in mobile view
(#9717)
# Pull Request Template
## Description
Currently, when a user navigates to a chat and attempts to access the
custom snooze modal, it is not visible, making it unable to set custom
snooze options. With this fix, the custom snooze modal will correctly
display even when a chat is open in mobile view.
**Cause of this issue**
The `` component is added to the ``
component. To accommodate small screen views, we are using the expanded
view. However, if we open a chat and select the custom snooze option
from the chat header in the message view, the ``
component is hidden in the `` component.
**Solution**
So, I moved the `` to the wrapper component
`` so we can use in all cases like,
1. Right-click to custom snooze
2. CMD bar custom snooze
3. Small screen custom snooze
---
.../dashboard/components/ChatList.vue | 58 -----------------
.../conversation/ConversationView.vue | 62 ++++++++++++++++++-
2 files changed, 60 insertions(+), 60 deletions(-)
diff --git a/app/javascript/dashboard/components/ChatList.vue b/app/javascript/dashboard/components/ChatList.vue
index eb410f7d5..ee5354027 100644
--- a/app/javascript/dashboard/components/ChatList.vue
+++ b/app/javascript/dashboard/components/ChatList.vue
@@ -111,15 +111,6 @@
@updateFolder="onUpdateSavedFilter"
/>
-
-
-
@@ -152,10 +143,6 @@ import {
isOnUnattendedView,
} from '../store/modules/conversations/helpers/actionHelpers';
import { CONVERSATION_EVENTS } from '../helper/AnalyticsHelper/events';
-import { CMD_SNOOZE_CONVERSATION } from 'dashboard/routes/dashboard/commands/commandBarBusEvents';
-import { findSnoozeTime } from 'dashboard/helper/snoozeHelpers';
-import { getUnixTime } from 'date-fns';
-import CustomSnoozeModal from 'dashboard/components/CustomSnoozeModal.vue';
import IntersectionObserver from './IntersectionObserver.vue';
export default {
@@ -170,7 +157,6 @@ export default {
ConversationBulkActions,
IntersectionObserver,
VirtualList,
- CustomSnoozeModal,
},
mixins: [
timeMixin,
@@ -247,7 +233,6 @@ export default {
root: this.$refs.conversationList,
rootMargin: '100px 0px 100px 0px',
},
- showCustomSnoozeModal: false,
itemComponent: ConversationItem,
// virtualListExtraProps is to pass the props to the conversationItem component.
@@ -283,7 +268,6 @@ export default {
campaigns: 'campaigns/getAllCampaigns',
labels: 'labels/getLabels',
selectedConversations: 'bulkActions/getSelectedConversationIds',
- contextMenuChatId: 'getContextMenuChatId',
}),
hasAppliedFilters() {
return this.appliedFilters.length !== 0;
@@ -517,11 +501,6 @@ export default {
this.$emitter.on('fetch_conversation_stats', () => {
this.$store.dispatch('conversationStats/get', this.conversationFilters);
});
-
- this.$emitter.on(CMD_SNOOZE_CONVERSATION, this.onCmdSnoozeConversation);
- },
- beforeDestroy() {
- this.$emitter.off(CMD_SNOOZE_CONVERSATION, this.onCmdSnoozeConversation);
},
methods: {
updateVirtualListProps(key, value) {
@@ -999,43 +978,6 @@ export default {
onContextMenuToggle(state) {
this.isContextMenuOpen = state;
},
- onCmdSnoozeConversation(snoozeType) {
- if (snoozeType === wootConstants.SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME) {
- this.showCustomSnoozeModal = true;
- } else {
- this.toggleStatus(
- wootConstants.STATUS_TYPE.SNOOZED,
- findSnoozeTime(snoozeType) || null
- );
- }
- },
- chooseSnoozeTime(customSnoozeTime) {
- this.showCustomSnoozeModal = false;
- if (customSnoozeTime) {
- this.toggleStatus(
- wootConstants.STATUS_TYPE.SNOOZED,
- getUnixTime(customSnoozeTime)
- );
- }
- },
- toggleStatus(status, snoozedUntil) {
- this.$store
- .dispatch('toggleStatus', {
- conversationId: this.currentChat?.id || this.contextMenuChatId,
- status,
- snoozedUntil,
- })
- .then(() => {
- this.$store.dispatch('setContextMenuChatId', null);
- this.showAlert(this.$t('CONVERSATION.CHANGE_STATUS'));
- });
- },
- hideCustomSnoozeModal() {
- // if we select custom snooze and then the custom snooze modal is open
- // Then if the custom snooze modal is closed and set the context menu chat id to null
- this.$store.dispatch('setContextMenuChatId', null);
- this.showCustomSnoozeModal = false;
- },
},
};
diff --git a/app/javascript/dashboard/routes/dashboard/conversation/ConversationView.vue b/app/javascript/dashboard/routes/dashboard/conversation/ConversationView.vue
index 2235b38f0..cd3cdfb80 100644
--- a/app/javascript/dashboard/routes/dashboard/conversation/ConversationView.vue
+++ b/app/javascript/dashboard/routes/dashboard/conversation/ConversationView.vue
@@ -22,25 +22,40 @@
:is-on-expanded-layout="isOnExpandedLayout"
@contact-panel-toggle="onToggleContactPanel"
/>
+