diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 000000000..1015fe997
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1,7 @@
+## All javascript files should be reviewed by pranav before merging
+*.js @pranavrajs
+*.vue @pranavrajs
+
+
+## All enterprise related files should be reviewed by sojan before merging
+/enterprise/* @sojan-official
diff --git a/.github/workflows/logging_percentage_check.yml b/.github/workflows/logging_percentage_check.yml
index 7b5627d45..e9f84c313 100644
--- a/.github/workflows/logging_percentage_check.yml
+++ b/.github/workflows/logging_percentage_check.yml
@@ -11,7 +11,7 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v2
+ uses: actions/checkout@v4
- name: Check for log lines and calculate percentage
run: |
diff --git a/.github/workflows/nightly_installer.yml b/.github/workflows/nightly_installer.yml
index 034c08e8c..d11fe6401 100644
--- a/.github/workflows/nightly_installer.yml
+++ b/.github/workflows/nightly_installer.yml
@@ -4,7 +4,7 @@
# # This action will try to install and setup
# # chatwoot on an Ubuntu 20.04 machine using
# # the linux installer script.
-# #
+# #
# # This is set to run daily at midnight.
# #
@@ -35,7 +35,7 @@ jobs:
run: |
sudo ./install.sh --install < input
- # disabling http verify for now as http
+ # disabling http verify for now as http
# access to port 3000 fails in gh action env
# - name: Verify
# if: always()
@@ -45,7 +45,7 @@ jobs:
# curl http://localhost:3000/api
- name: Upload chatwoot setup log file as an artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
if: always()
with:
name: chatwoot-setup-log-file
diff --git a/.github/workflows/publish_codespace_image.yml b/.github/workflows/publish_codespace_image.yml
index 60632d906..647608473 100644
--- a/.github/workflows/publish_codespace_image.yml
+++ b/.github/workflows/publish_codespace_image.yml
@@ -8,7 +8,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v4
- name: Login to GitHub Container Registry
uses: docker/login-action@v1
diff --git a/.github/workflows/publish_foss_docker.yml b/.github/workflows/publish_foss_docker.yml
index 2ddaba7e5..d48b82a58 100644
--- a/.github/workflows/publish_foss_docker.yml
+++ b/.github/workflows/publish_foss_docker.yml
@@ -21,7 +21,7 @@ jobs:
GIT_REF: ${{ github.head_ref || github.ref_name }} # ref_name to get tags/branches
steps:
- name: Checkout
- uses: actions/checkout@v2
+ uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
diff --git a/.github/workflows/run_foss_spec.yml b/.github/workflows/run_foss_spec.yml
index 7a32f3fd1..b0b2372ae 100644
--- a/.github/workflows/run_foss_spec.yml
+++ b/.github/workflows/run_foss_spec.yml
@@ -41,7 +41,7 @@ jobs:
options: --entrypoint redis-server
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.ref }}
repository: ${{ github.event.pull_request.head.repo.full_name }}
@@ -50,7 +50,7 @@ jobs:
with:
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
- - uses: actions/setup-node@v3
+ - uses: actions/setup-node@v4
with:
node-version: 20
cache: yarn
@@ -76,11 +76,11 @@ jobs:
- name: Run backend tests
run: |
bundle exec rspec --profile=10 --format documentation
- env:
+ env:
NODE_OPTIONS: --openssl-legacy-provider
- name: Upload rails log folder
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
if: always()
with:
name: rails-log-folder
diff --git a/.github/workflows/run_response_bot_spec.yml b/.github/workflows/run_response_bot_spec.yml
index 6fd6a7b22..77b96c48a 100644
--- a/.github/workflows/run_response_bot_spec.yml
+++ b/.github/workflows/run_response_bot_spec.yml
@@ -40,7 +40,7 @@ jobs:
options: --entrypoint redis-server
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.ref }}
repository: ${{ github.event.pull_request.head.repo.full_name }}
@@ -49,7 +49,7 @@ jobs:
with:
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
- - uses: actions/setup-node@v3
+ - uses: actions/setup-node@v4
with:
node-version: 20
cache: yarn
@@ -77,7 +77,7 @@ jobs:
--format documentation
- name: Upload rails log folder
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
if: always()
with:
name: rails-log-folder
diff --git a/.github/workflows/size-limit.yml b/.github/workflows/size-limit.yml
index 01d72339d..0526aeedb 100644
--- a/.github/workflows/size-limit.yml
+++ b/.github/workflows/size-limit.yml
@@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-20.04
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.ref }}
repository: ${{ github.event.pull_request.head.repo.full_name }}
@@ -19,7 +19,7 @@ jobs:
with:
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
- - uses: actions/setup-node@v3
+ - uses: actions/setup-node@v4
with:
node-version: 20
cache: 'yarn'
@@ -31,7 +31,7 @@ jobs:
run: |
rm -rf enterprise
rm -rf spec/enterprise
-
+
- name: Run asset compile
run: bundle exec rake assets:precompile
env:
diff --git a/Gemfile.lock b/Gemfile.lock
index 74b281b43..35e1e2a48 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -316,16 +316,16 @@ GEM
google-cloud-translate-v3 (0.6.0)
gapic-common (>= 0.17.1, < 2.a)
google-cloud-errors (~> 1.0)
- google-protobuf (3.22.3)
- google-protobuf (3.22.3-arm64-darwin)
- google-protobuf (3.22.3-x86_64-darwin)
- google-protobuf (3.22.3-x86_64-linux)
+ google-protobuf (3.25.2)
+ google-protobuf (3.25.2-arm64-darwin)
+ google-protobuf (3.25.2-x86_64-darwin)
+ google-protobuf (3.25.2-x86_64-linux)
googleapis-common-protos (1.4.0)
google-protobuf (~> 3.14)
googleapis-common-protos-types (~> 1.2)
grpc (~> 1.27)
- googleapis-common-protos-types (1.6.0)
- google-protobuf (~> 3.14)
+ googleapis-common-protos-types (1.11.0)
+ google-protobuf (~> 3.18)
googleauth (1.5.2)
faraday (>= 0.17.3, < 3.a)
jwt (>= 1.4, < 3.0)
@@ -335,13 +335,13 @@ GEM
signet (>= 0.16, < 2.a)
groupdate (6.2.1)
activesupport (>= 5.2)
- grpc (1.54.0)
+ grpc (1.54.3)
google-protobuf (~> 3.21)
googleapis-common-protos-types (~> 1.0)
- grpc (1.54.0-x86_64-darwin)
+ grpc (1.54.3-x86_64-darwin)
google-protobuf (~> 3.21)
googleapis-common-protos-types (~> 1.0)
- grpc (1.54.0-x86_64-linux)
+ grpc (1.54.3-x86_64-linux)
google-protobuf (~> 3.21)
googleapis-common-protos-types (~> 1.0)
haikunator (1.1.1)
diff --git a/app/controllers/concerns/access_token_auth_helper.rb b/app/controllers/concerns/access_token_auth_helper.rb
index 0a6c89860..cd760f7ce 100644
--- a/app/controllers/concerns/access_token_auth_helper.rb
+++ b/app/controllers/concerns/access_token_auth_helper.rb
@@ -1,7 +1,8 @@
module AccessTokenAuthHelper
BOT_ACCESSIBLE_ENDPOINTS = {
- 'api/v1/accounts/conversations' => %w[toggle_status create],
- 'api/v1/accounts/conversations/messages' => ['create']
+ 'api/v1/accounts/conversations' => %w[toggle_status toggle_priority create],
+ 'api/v1/accounts/conversations/messages' => ['create'],
+ 'api/v1/accounts/conversations/assignments' => ['create']
}.freeze
def ensure_access_token
diff --git a/app/controllers/concerns/ensure_current_account_helper.rb b/app/controllers/concerns/ensure_current_account_helper.rb
index 5d02e96c8..3baf9ee1e 100644
--- a/app/controllers/concerns/ensure_current_account_helper.rb
+++ b/app/controllers/concerns/ensure_current_account_helper.rb
@@ -25,6 +25,6 @@ module EnsureCurrentAccountHelper
end
def account_accessible_for_bot?(account)
- render_unauthorized('You are not authorized to access this account') unless @resource.agent_bot_inboxes.find_by(account_id: account.id)
+ render_unauthorized('Bot is not authorized to access this account') unless @resource.agent_bot_inboxes.find_by(account_id: account.id)
end
end
diff --git a/app/controllers/super_admin/instance_statuses_controller.rb b/app/controllers/super_admin/instance_statuses_controller.rb
index a1dc458ae..b0e97b95d 100644
--- a/app/controllers/super_admin/instance_statuses_controller.rb
+++ b/app/controllers/super_admin/instance_statuses_controller.rb
@@ -28,8 +28,7 @@ class SuperAdmin::InstanceStatusesController < SuperAdmin::ApplicationController
end
def sha
- sha = `git rev-parse HEAD`
- @metrics['Git SHA'] = sha.presence || 'n/a'
+ @metrics['Git SHA'] = GIT_HASH
end
def postgres_status
diff --git a/app/helpers/api/v2/accounts/heatmap_helper.rb b/app/helpers/api/v2/accounts/heatmap_helper.rb
index 597135f47..58dade28d 100644
--- a/app/helpers/api/v2/accounts/heatmap_helper.rb
+++ b/app/helpers/api/v2/accounts/heatmap_helper.rb
@@ -15,8 +15,8 @@ module Api::V2::Accounts::HeatmapHelper
dates = data.pluck(:date).uniq.sort
# add the dates as the first row, leave an empty cell for the hour column
- # e.g. [nil, '2023-01-01', '2023-1-02', '2023-01-03']
- result_arr << ([nil] + dates)
+ # e.g. ['Start of the hour', '2023-01-01', '2023-1-02', '2023-01-03']
+ result_arr << (['Start of the hour'] + dates)
# group the data by hour, we do not need to sort it, because the data is already sorted
# given it starts from the beginning of the day
@@ -25,7 +25,7 @@ module Api::V2::Accounts::HeatmapHelper
# value = [{date: 2023-01-01, value: 1}, {date: 2023-01-02, value: 1}, {date: 2023-01-03, value: 1}, ...]
data.group_by { |d| d[:hour] }.each do |hour, items|
# create a new row for each hour
- row = [hour]
+ row = [format('%02d:00', hour)]
# group the items by date, so we can easily access the value for each date
# grouped values will be a hasg with the date as the key, and the value as the value
@@ -37,7 +37,7 @@ module Api::V2::Accounts::HeatmapHelper
row << (grouped_values[date][0][:value] if grouped_values[date].is_a?(Array))
end
- # row will look like [22, 0, 0, 1, 4, 6, 7, 4]
+ # row will look like ['22:00', 0, 0, 1, 4, 6, 7, 4]
# add the row to the result array
result_arr << row
@@ -46,12 +46,12 @@ module Api::V2::Accounts::HeatmapHelper
# return the resultant array
# the result looks like this
# [
- # [nil, '2023-01-01', '2023-1-02', '2023-01-03'],
- # [0, 0, 0, 0],
- # [1, 0, 0, 0],
- # [2, 0, 0, 0],
- # [3, 0, 0, 0],
- # [4, 0, 0, 0],
+ # ['Start of the hour', '2023-01-01', '2023-1-02', '2023-01-03'],
+ # ['00:00', 0, 0, 0],
+ # ['01:00', 0, 0, 0],
+ # ['02:00', 0, 0, 0],
+ # ['03:00', 0, 0, 0],
+ # ['04:00', 0, 0, 0],
# ]
result_arr
end
diff --git a/app/javascript/dashboard/api/notifications.js b/app/javascript/dashboard/api/notifications.js
index 183642742..65fc937b7 100644
--- a/app/javascript/dashboard/api/notifications.js
+++ b/app/javascript/dashboard/api/notifications.js
@@ -6,8 +6,15 @@ class NotificationsAPI extends ApiClient {
super('notifications', { accountScoped: true });
}
- get(page) {
- return axios.get(`${this.url}?page=${page}`);
+ get({ page, status, type, sortOrder }) {
+ return axios.get(this.url, {
+ params: {
+ page,
+ status,
+ type,
+ sort_order: sortOrder,
+ },
+ });
}
getNotifications(contactId) {
diff --git a/app/javascript/dashboard/api/specs/notifications.spec.js b/app/javascript/dashboard/api/specs/notifications.spec.js
index 5bdf88d7f..bc06eaa2b 100644
--- a/app/javascript/dashboard/api/specs/notifications.spec.js
+++ b/app/javascript/dashboard/api/specs/notifications.spec.js
@@ -28,10 +28,20 @@ describe('#NotificationAPI', () => {
});
it('#get', () => {
- notificationsAPI.get(1);
- expect(axiosMock.get).toHaveBeenCalledWith(
- '/api/v1/notifications?page=1'
- );
+ notificationsAPI.get({
+ page: 1,
+ status: 'read',
+ type: 'Conversation',
+ sortOrder: 'desc',
+ });
+ expect(axiosMock.get).toHaveBeenCalledWith('/api/v1/notifications', {
+ params: {
+ page: 1,
+ status: 'read',
+ type: 'Conversation',
+ sort_order: 'desc',
+ },
+ });
});
it('#getNotifications', () => {
@@ -65,5 +75,30 @@ describe('#NotificationAPI', () => {
'/api/v1/notifications/read_all'
);
});
+
+ it('#snooze', () => {
+ notificationsAPI.snooze({ id: 1, snoozedUntil: 12332211 });
+ expect(axiosMock.post).toHaveBeenCalledWith(
+ '/api/v1/notifications/1/snooze',
+ {
+ snoozed_until: 12332211,
+ }
+ );
+ });
+
+ it('#delete', () => {
+ notificationsAPI.delete(1);
+ expect(axiosMock.delete).toHaveBeenCalledWith('/api/v1/notifications/1');
+ });
+
+ it('#deleteAll', () => {
+ notificationsAPI.deleteAll({ type: 'all' });
+ expect(axiosMock.post).toHaveBeenCalledWith(
+ '/api/v1/notifications/destroy_all',
+ {
+ type: 'all',
+ }
+ );
+ });
});
});
diff --git a/app/javascript/dashboard/constants/globals.js b/app/javascript/dashboard/constants/globals.js
index 84c789151..c0b0bdcf0 100644
--- a/app/javascript/dashboard/constants/globals.js
+++ b/app/javascript/dashboard/constants/globals.js
@@ -46,6 +46,19 @@ export default {
},
EXAMPLE_URL: 'https://example.com',
EXAMPLE_WEBHOOK_URL: 'https://example/api/webhook',
+ INBOX_SORT_BY: {
+ NEWEST: 'desc',
+ OLDEST: 'asc',
+ },
+ INBOX_DISPLAY_BY: {
+ SNOOZED: 'snoozed',
+ READ: 'read',
+ },
+ INBOX_FILTER_TYPE: {
+ STATUS: 'status',
+ TYPE: 'type',
+ SORT_ORDER: 'sort_order',
+ },
};
export const DEFAULT_REDIRECT_URL = '/app/';
export const ONBOARDING_START_URL = '/app/start/setup-profile';
diff --git a/app/javascript/dashboard/routes/dashboard/conversation/contact/ContactInfo.vue b/app/javascript/dashboard/routes/dashboard/conversation/contact/ContactInfo.vue
index eb2bc2bb4..ad2ea5d25 100644
--- a/app/javascript/dashboard/routes/dashboard/conversation/contact/ContactInfo.vue
+++ b/app/javascript/dashboard/routes/dashboard/conversation/contact/ContactInfo.vue
@@ -306,7 +306,7 @@ export default {
});
} else if (isAInboxViewRoute(this.$route.name)) {
this.$router.push({
- name: 'inbox-view',
+ name: 'inbox_view',
});
} else if (this.$route.name !== 'contacts_dashboard') {
this.$router.push({
diff --git a/app/javascript/dashboard/routes/dashboard/inbox/InboxList.vue b/app/javascript/dashboard/routes/dashboard/inbox/InboxList.vue
index e0924b9c0..bb0f2e7df 100644
--- a/app/javascript/dashboard/routes/dashboard/inbox/InboxList.vue
+++ b/app/javascript/dashboard/routes/dashboard/inbox/InboxList.vue
@@ -3,13 +3,13 @@
class="flex flex-col h-full w-full ltr:border-r border-slate-50 dark:border-slate-800/50"
:class="isOnExpandedLayout ? '' : 'min-w-[360px] max-w-[360px]'"
>
-