diff --git a/.circleci/config.yml b/.circleci/config.yml
index c67063ae6..cdddc4a06 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -7,7 +7,7 @@ defaults: &defaults
working_directory: ~/build
docker:
# specify the version you desire here
- - image: cimg/ruby:3.2.2-browsers
+ - image: cimg/ruby:3.3.3-browsers
# Specify service dependencies here if necessary
# CircleCI maintains a library of pre-built images
diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml
index 17021d1e7..a804bb15c 100644
--- a/.devcontainer/docker-compose.yml
+++ b/.devcontainer/docker-compose.yml
@@ -12,7 +12,7 @@ services:
args:
VARIANT: "ubuntu-22.04"
NODE_VERSION: "20.9.0"
- RUBY_VERSION: "3.2.2"
+ RUBY_VERSION: "3.3.3"
# On Linux, you may need to update USER_UID and USER_GID below if not your local UID is not 1000.
USER_UID: "1000"
USER_GID: "1000"
@@ -25,7 +25,7 @@ services:
args:
VARIANT: "ubuntu-22.04"
NODE_VERSION: "20.9.0"
- RUBY_VERSION: "3.2.2"
+ RUBY_VERSION: "3.3.3"
# On Linux, you may need to update USER_UID and USER_GID below if not your local UID is not 1000.
USER_UID: "1000"
USER_GID: "1000"
diff --git a/.env.example b/.env.example
index 1b57141f0..befcde463 100644
--- a/.env.example
+++ b/.env.example
@@ -85,6 +85,8 @@ SMTP_OPENSSL_VERIFY_MODE=peer
# Comment out the following environment variables if required by your SMTP server
# SMTP_TLS=
# SMTP_SSL=
+# SMTP_OPEN_TIMEOUT
+# SMTP_READ_TIMEOUT
# Mail Incoming
# This is the domain set for the reply emails when conversation continuity is enabled
diff --git a/.ruby-version b/.ruby-version
index be94e6f53..619b53766 100644
--- a/.ruby-version
+++ b/.ruby-version
@@ -1 +1 @@
-3.2.2
+3.3.3
diff --git a/Gemfile b/Gemfile
index 302094e8f..f690e6876 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,6 +1,6 @@
source 'https://rubygems.org'
-ruby '3.2.2'
+ruby '3.3.3'
##-- base gems for rails --##
gem 'rack-cors', '2.0.0', require: 'rack/cors'
@@ -111,12 +111,12 @@ gem 'elastic-apm', require: false
gem 'newrelic_rpm', require: false
gem 'newrelic-sidekiq-metrics', '>= 1.6.2', require: false
gem 'scout_apm', require: false
-gem 'sentry-rails', '>= 5.14.0', require: false
+gem 'sentry-rails', '>= 5.18.1', require: false
gem 'sentry-ruby', require: false
-gem 'sentry-sidekiq', '>= 5.15.0', require: false
+gem 'sentry-sidekiq', '>= 5.18.1', 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'
@@ -228,7 +228,7 @@ group :development, :test do
gem 'mock_redis'
gem 'pry-rails'
gem 'rspec_junit_formatter'
- gem 'rspec-rails', '>= 6.0.3'
+ gem 'rspec-rails', '>= 6.1.3'
gem 'rubocop', require: false
gem 'rubocop-performance', require: false
gem 'rubocop-rails', require: false
diff --git a/Gemfile.lock b/Gemfile.lock
index b2b319966..91d3b3d8b 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -150,13 +150,13 @@ GEM
statsd-ruby (~> 1.1)
base64 (0.2.0)
bcrypt (3.1.20)
- bigdecimal (3.1.7)
+ bigdecimal (3.1.8)
bindex (0.8.1)
bootsnap (1.16.0)
msgpack (~> 1.2)
brakeman (5.4.1)
browser (5.3.1)
- builder (3.2.4)
+ builder (3.3.0)
bullet (7.0.7)
activesupport (>= 3.0.0)
uniform_notifier (~> 1.11)
@@ -169,12 +169,14 @@ GEM
climate_control (1.2.0)
coderay (1.1.3)
commonmarker (0.23.10)
- concurrent-ruby (1.3.1)
+ concurrent-ruby (1.3.3)
connection_pool (2.4.1)
crack (0.4.5)
rexml
crass (1.0.6)
- csv-safe (3.2.1)
+ csv (3.3.0)
+ csv-safe (3.3.1)
+ csv (~> 3.0)
cypress-on-rails (1.16.0)
rack
database_cleaner (2.0.2)
@@ -183,13 +185,16 @@ GEM
activerecord (>= 5.a)
database_cleaner-core (~> 2.0.0)
database_cleaner-core (2.0.1)
- date (3.3.4)
- ddtrace (1.11.1)
- debase-ruby_core_source (>= 0.10.16, <= 3.2.0)
- libdatadog (~> 2.0.0.1.0)
- libddwaf (~> 1.8.2.0.0)
+ datadog-ci (0.8.3)
msgpack
- debase-ruby_core_source (3.2.0)
+ date (3.3.4)
+ ddtrace (1.23.2)
+ datadog-ci (~> 0.8.1)
+ debase-ruby_core_source (= 3.3.1)
+ libdatadog (~> 7.0.0.1.0)
+ libddwaf (~> 1.14.0.0.0)
+ msgpack
+ debase-ruby_core_source (3.3.1)
debug (1.8.0)
irb (>= 1.5.0)
reline (>= 0.3.1)
@@ -223,7 +228,7 @@ GEM
http (>= 3.0)
ruby2_keywords
email_reply_trimmer (0.1.13)
- erubi (1.12.0)
+ erubi (1.13.0)
et-orbi (1.2.7)
tzinfo
execjs (2.8.1)
@@ -416,15 +421,15 @@ GEM
addressable (~> 2.8)
letter_opener (1.8.1)
launchy (>= 2.2, < 3)
- libdatadog (2.0.0.1.0)
- libdatadog (2.0.0.1.0-x86_64-linux)
- libddwaf (1.8.2.0.0)
+ libdatadog (7.0.0.1.0)
+ libdatadog (7.0.0.1.0-x86_64-linux)
+ libddwaf (1.14.0.0.0)
ffi (~> 1.0)
- libddwaf (1.8.2.0.0-arm64-darwin)
+ libddwaf (1.14.0.0.0-arm64-darwin)
ffi (~> 1.0)
- libddwaf (1.8.2.0.0-x86_64-darwin)
+ libddwaf (1.14.0.0.0-x86_64-darwin)
ffi (~> 1.0)
- libddwaf (1.8.2.0.0-x86_64-linux)
+ libddwaf (1.14.0.0.0-x86_64-linux)
ffi (~> 1.0)
line-bot-api (1.28.0)
liquid (5.4.0)
@@ -434,6 +439,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)
@@ -460,7 +466,7 @@ GEM
mini_magick (4.12.0)
mini_mime (1.1.5)
mini_portile2 (2.8.7)
- minitest (5.23.1)
+ minitest (5.24.1)
mock_redis (0.36.0)
ruby2_keywords
msgpack (1.7.0)
@@ -489,14 +495,14 @@ GEM
newrelic_rpm (9.6.0)
base64
nio4r (2.7.3)
- nokogiri (1.16.5)
+ nokogiri (1.16.6)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
- nokogiri (1.16.5-arm64-darwin)
+ nokogiri (1.16.6-arm64-darwin)
racc (~> 1.4)
- nokogiri (1.16.5-x86_64-darwin)
+ nokogiri (1.16.6-x86_64-darwin)
racc (~> 1.4)
- nokogiri (1.16.5-x86_64-linux)
+ nokogiri (1.16.6-x86_64-linux)
racc (~> 1.4)
oauth (1.1.0)
oauth-tty (~> 1.0, >= 1.0.1)
@@ -603,7 +609,7 @@ GEM
ffi (~> 1.0)
redis (5.0.6)
redis-client (>= 0.9.0)
- redis-client (0.22.1)
+ redis-client (0.22.2)
connection_pool
redis-namespace (1.10.0)
redis (>= 4)
@@ -631,13 +637,13 @@ GEM
strscan (>= 3.0.9)
rspec-core (3.13.0)
rspec-support (~> 3.13.0)
- rspec-expectations (3.13.0)
+ rspec-expectations (3.13.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-mocks (3.13.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
- rspec-rails (6.1.2)
+ rspec-rails (6.1.3)
actionpack (>= 6.1)
activesupport (>= 6.1)
railties (>= 6.1)
@@ -703,23 +709,24 @@ GEM
activesupport (>= 4)
selectize-rails (0.12.6)
semantic_range (3.0.0)
- sentry-rails (5.17.3)
+ sentry-rails (5.18.1)
railties (>= 5.0)
- sentry-ruby (~> 5.17.3)
- sentry-ruby (5.17.3)
+ sentry-ruby (~> 5.18.1)
+ sentry-ruby (5.18.1)
bigdecimal
concurrent-ruby (~> 1.0, >= 1.0.2)
- sentry-sidekiq (5.17.3)
- sentry-ruby (~> 5.17.3)
+ sentry-sidekiq (5.18.1)
+ sentry-ruby (~> 5.18.1)
sidekiq (>= 3.0)
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)
@@ -819,7 +826,7 @@ GEM
working_hours (1.4.1)
activesupport (>= 3.2)
tzinfo
- zeitwerk (2.6.15)
+ zeitwerk (2.6.16)
PLATFORMS
arm64-darwin-20
@@ -922,7 +929,7 @@ DEPENDENCIES
responders (>= 3.1.1)
rest-client
reverse_markdown
- rspec-rails (>= 6.0.3)
+ rspec-rails (>= 6.1.3)
rspec_junit_formatter
rubocop
rubocop-performance
@@ -931,11 +938,11 @@ DEPENDENCIES
scout_apm
scss_lint
seed_dump
- sentry-rails (>= 5.14.0)
+ sentry-rails (>= 5.18.1)
sentry-ruby
- sentry-sidekiq (>= 5.15.0)
+ sentry-sidekiq (>= 5.18.1)
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)
@@ -960,7 +967,7 @@ DEPENDENCIES
working_hours
RUBY VERSION
- ruby 3.2.2p185
+ ruby 3.3.3p89
BUNDLED WITH
- 2.4.6
+ 2.5.14
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/controllers/super_admin/app_configs_controller.rb b/app/controllers/super_admin/app_configs_controller.rb
index 9d9494fc4..b8f3bd9a9 100644
--- a/app/controllers/super_admin/app_configs_controller.rb
+++ b/app/controllers/super_admin/app_configs_controller.rb
@@ -40,7 +40,7 @@ class SuperAdmin::AppConfigsController < SuperAdmin::ApplicationController
when 'email'
['MAILER_INBOUND_EMAIL_DOMAIN']
else
- %w[ENABLE_ACCOUNT_SIGNUP]
+ %w[ENABLE_ACCOUNT_SIGNUP FIREBASE_PROJECT_ID FIREBASE_CREDENTIALS]
end
end
end
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"
/>
-
');
+ }
+
+ return '';
},
displayQuotedButton() {
if (this.emailMessageContent.includes('
{ }; // Add the "None" option to the agent list -export const agentList = agents => [ +export const addNoneToList = agents => [ { id: 'nil', name: 'None', @@ -137,8 +137,8 @@ export const getActionOptions = ({ type, }) => { const actionsMap = { - assign_agent: agentList(agents), - assign_team: teams, + assign_agent: addNoneToList(agents), + assign_team: addNoneToList(teams), send_email_to_team: teams, add_label: generateConditionOptions(labels, 'title'), remove_label: generateConditionOptions(labels, 'title'), 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/i18n/locale/en/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/en/inboxMgmt.json index 38ebfb122..82e6e7c2b 100644 --- a/app/javascript/dashboard/i18n/locale/en/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/en/inboxMgmt.json @@ -367,7 +367,6 @@ "DESCRIPTION": "Click on the Sign in with Microsoft button to get started. You will redirected to the email sign in page. Once you accept the requested permissions, you would be redirected back to the inbox creation step.", "EMAIL_PLACEHOLDER": "Enter email address", "SIGN_IN": "Sign in with Microsoft", - "HELP": "To add your Microsoft account as a channel, you need to authenticate your Microsoft account by clicking on 'Sign in with Microsoft' ", "ERROR_MESSAGE": "There was an error connecting to Microsoft, please try again" }, "GOOGLE": { @@ -375,7 +374,6 @@ "DESCRIPTION": "Click on the Sign in with Google button to get started. You will redirected to the email sign in page. Once you accept the requested permissions, you would be redirected back to the inbox creation step.", "SIGN_IN": "Sign in with Google", "EMAIL_PLACEHOLDER": "Enter email address", - "HELP": "To add your Google account as a channel, you need to authenticate your Google account by clicking on 'Sign in with Google' ", "ERROR_MESSAGE": "There was an error connecting to Google, please try again" } }, 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/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" /> ++ diff --git a/app/javascript/dashboard/routes/dashboard/conversation/contact/ContactForm.vue b/app/javascript/dashboard/routes/dashboard/conversation/contact/ContactForm.vue index 176085339..66df0d015 100644 --- a/app/javascript/dashboard/routes/dashboard/conversation/contact/ContactForm.vue +++ b/app/javascript/dashboard/routes/dashboard/conversation/contact/ContactForm.vue @@ -117,7 +117,7 @@ />+ - +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/channels/Email.vue b/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/Email.vue index 34a5d2070..375e5aefb 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/Email.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/Email.vue @@ -20,58 +20,59 @@+ - diff --git a/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/emailChannels/Google.vue b/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/emailChannels/Google.vue index 9fb3fe978..b0588bdd6 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/emailChannels/Google.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/emailChannels/Google.vue @@ -1,55 +1,18 @@ - - -+- - diff --git a/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/emailChannels/Microsoft.vue b/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/emailChannels/Microsoft.vue index faf83dace..ee0b29360 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/emailChannels/Microsoft.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/emailChannels/Microsoft.vue @@ -1,75 +1,19 @@ - - -- - - + +- - + diff --git a/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/emailChannels/OAuthChannel.vue b/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/emailChannels/OAuthChannel.vue new file mode 100644 index 000000000..b6ccef365 --- /dev/null +++ b/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/emailChannels/OAuthChannel.vue @@ -0,0 +1,89 @@ + + + ++ 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(); }; diff --git a/app/javascript/packs/sdk.js b/app/javascript/packs/sdk.js index 84cf5fe2d..0aac9104e 100755 --- a/app/javascript/packs/sdk.js +++ b/app/javascript/packs/sdk.js @@ -62,6 +62,7 @@ const runSDK = ({ baseUrl, websiteToken }) => { type: getBubbleView(chatwootSettings.type), launcherTitle: chatwootSettings.launcherTitle || '', showPopoutButton: chatwootSettings.showPopoutButton || false, + showUnreadMessagesDialog: chatwootSettings.showUnreadMessagesDialog ?? true, widgetStyle: getWidgetStyle(chatwootSettings.widgetStyle) || 'standard', resetTriggered: false, darkMode: getDarkMode(chatwootSettings.darkMode), diff --git a/app/javascript/sdk/IFrameHelper.js b/app/javascript/sdk/IFrameHelper.js index 3687fa311..275d082f5 100644 --- a/app/javascript/sdk/IFrameHelper.js +++ b/app/javascript/sdk/IFrameHelper.js @@ -160,6 +160,7 @@ export const IFrameHelper = { showPopoutButton: window.$chatwoot.showPopoutButton, widgetStyle: window.$chatwoot.widgetStyle, darkMode: window.$chatwoot.darkMode, + showUnreadMessagesDialog: window.$chatwoot.showUnreadMessagesDialog, campaignsSnoozedTill, }); IFrameHelper.onLoad({ 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); }); diff --git a/app/javascript/widget/App.vue b/app/javascript/widget/App.vue index ddfcc8ecb..072323d53 100755 --- a/app/javascript/widget/App.vue +++ b/app/javascript/widget/App.vue @@ -71,6 +71,7 @@ export default { messageCount: 'conversation/getMessageCount', unreadMessageCount: 'conversation/getUnreadMessageCount', isWidgetStyleFlat: 'appConfig/isWidgetStyleFlat', + showUnreadMessagesDialog: 'appConfig/getShowUnreadMessagesDialog', }), isIFrame() { return IFrameHelper.isIFrame(); @@ -209,8 +210,13 @@ export default { }, setUnreadView() { const { unreadMessageCount } = this; - - if (this.isIFrame && unreadMessageCount > 0 && !this.isWidgetOpen) { + if (!this.showUnreadMessagesDialog) { + this.handleUnreadNotificationDot(); + } else if ( + this.isIFrame && + unreadMessageCount > 0 && + !this.isWidgetOpen + ) { this.replaceRoute('unread-messages').then(() => { this.setIframeHeight(true); IFrameHelper.sendMessage({ event: 'setUnreadMode' }); 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 @@ />+ +