From c1f6d9f76f7b03eb865c52d57f96a4528afe0282 Mon Sep 17 00:00:00 2001 From: Sojan Jose Date: Wed, 5 Mar 2025 16:32:54 -0800 Subject: [PATCH 1/3] feat: Add the ability to filter items in Super Admin panel (#11020) --- Gemfile.lock | 2 +- .../administrate/custom_styles.scss | 1 - app/dashboards/account_dashboard.rb | 6 +- app/dashboards/user_dashboard.rb | 7 ++- .../super_admin/application/_filters.html.erb | 63 +++++++++++++++++++ .../super_admin/application/_search.html.erb | 24 +++++++ .../super_admin/application/index.html.erb | 47 ++++++++------ 7 files changed, 127 insertions(+), 23 deletions(-) create mode 100644 app/views/super_admin/application/_filters.html.erb create mode 100644 app/views/super_admin/application/_search.html.erb diff --git a/Gemfile.lock b/Gemfile.lock index e9a573816..8591a0c34 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -799,7 +799,7 @@ GEM unf_ext (0.0.8.2) unicode-display_width (2.4.2) uniform_notifier (1.16.0) - uri (0.13.0) + uri (1.0.3) uri_template (0.7.0) valid_email2 (5.2.6) activemodel (>= 3.2) diff --git a/app/assets/stylesheets/administrate/custom_styles.scss b/app/assets/stylesheets/administrate/custom_styles.scss index 5e6d803d8..00f1a058c 100644 --- a/app/assets/stylesheets/administrate/custom_styles.scss +++ b/app/assets/stylesheets/administrate/custom_styles.scss @@ -10,7 +10,6 @@ .icon-container { margin-right: 2px; - } .value-container { diff --git a/app/dashboards/account_dashboard.rb b/app/dashboards/account_dashboard.rb index b566551f4..f7b04a167 100644 --- a/app/dashboards/account_dashboard.rb +++ b/app/dashboards/account_dashboard.rb @@ -78,7 +78,11 @@ class AccountDashboard < Administrate::BaseDashboard # COLLECTION_FILTERS = { # open: ->(resources) { resources.where(open: true) } # }.freeze - COLLECTION_FILTERS = {}.freeze + COLLECTION_FILTERS = { + active: ->(resources) { resources.where(status: :active) }, + suspended: ->(resources) { resources.where(status: :suspended) }, + recent: ->(resources) { resources.where('created_at > ?', 30.days.ago) } + }.freeze # Overwrite this method to customize how accounts are displayed # across all pages of the admin dashboard. diff --git a/app/dashboards/user_dashboard.rb b/app/dashboards/user_dashboard.rb index 6b2129eed..8abdefd1a 100644 --- a/app/dashboards/user_dashboard.rb +++ b/app/dashboards/user_dashboard.rb @@ -94,7 +94,12 @@ class UserDashboard < Administrate::BaseDashboard # COLLECTION_FILTERS = { # open: ->(resources) { resources.where(open: true) } # }.freeze - COLLECTION_FILTERS = {}.freeze + COLLECTION_FILTERS = { + super_admin: ->(resources) { resources.where(type: 'SuperAdmin') }, + confirmed: ->(resources) { resources.where.not(confirmed_at: nil) }, + unconfirmed: ->(resources) { resources.where(confirmed_at: nil) }, + recent: ->(resources) { resources.where('created_at > ?', 30.days.ago) } + }.freeze # Overwrite this method to customize how users are displayed # across all pages of the admin dashboard. diff --git a/app/views/super_admin/application/_filters.html.erb b/app/views/super_admin/application/_filters.html.erb new file mode 100644 index 000000000..f2e339ebe --- /dev/null +++ b/app/views/super_admin/application/_filters.html.erb @@ -0,0 +1,63 @@ +<%# +# Filters + +This partial is used on the `index` page to display available filters +for a collection of resources. + +## Local variables: + +- `page`: + An instance of [Administrate::Page::Collection][1]. + Contains helper methods to help display a table, + and knows which attributes should be displayed in the resource's table. + +[1]: http://www.rubydoc.info/gems/administrate/Administrate/Page/Collection +%> + +<% + # Get the dashboard class name from the resource name + resource_name = page.resource_name.classify + dashboard_class_name = "#{resource_name}Dashboard" + dashboard_class = dashboard_class_name.constantize + + # Get the current filter if any + current_filter = nil + if params[:search] && params[:search].include?(':') + current_filter = params[:search].split(':').first + end +%> + +<% if dashboard_class.const_defined?(:COLLECTION_FILTERS) && !dashboard_class::COLLECTION_FILTERS.empty? %> +
+
+
+ + + +
+
+ + <% if current_filter %> + × + <% end %> +
+
+
+ + +<% end %> \ No newline at end of file diff --git a/app/views/super_admin/application/_search.html.erb b/app/views/super_admin/application/_search.html.erb new file mode 100644 index 000000000..a38c5a9c5 --- /dev/null +++ b/app/views/super_admin/application/_search.html.erb @@ -0,0 +1,24 @@ + \ No newline at end of file diff --git a/app/views/super_admin/application/index.html.erb b/app/views/super_admin/application/index.html.erb index f73b3033c..89d40d697 100644 --- a/app/views/super_admin/application/index.html.erb +++ b/app/views/super_admin/application/index.html.erb @@ -28,27 +28,36 @@ It renders the `_table` partial to display details about the resources. <% end %> From d017156f32e9a02a43f06d014df24d1025713606 Mon Sep 17 00:00:00 2001 From: Pranav Date: Wed, 5 Mar 2025 17:10:24 -0800 Subject: [PATCH 2/3] fix: Disable syncing IMAP if the account is suspended (#11031) This PR disables the IMAP syncing if the account is suspended. --- Gemfile.lock | 2 +- .../inboxes/fetch_imap_email_inboxes_job.rb | 11 +++++-- .../fetch_imap_email_inboxes_job_spec.rb | 33 ++++++++++++++++--- 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 8591a0c34..857319fc4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -561,7 +561,7 @@ GEM activesupport (>= 3.0.0) raabro (1.4.0) racc (1.8.1) - rack (2.2.11) + rack (2.2.12) rack-attack (6.7.0) rack (>= 1.0, < 4) rack-contrib (2.5.0) diff --git a/app/jobs/inboxes/fetch_imap_email_inboxes_job.rb b/app/jobs/inboxes/fetch_imap_email_inboxes_job.rb index b360940e3..56e8c2235 100644 --- a/app/jobs/inboxes/fetch_imap_email_inboxes_job.rb +++ b/app/jobs/inboxes/fetch_imap_email_inboxes_job.rb @@ -2,8 +2,15 @@ class Inboxes::FetchImapEmailInboxesJob < ApplicationJob queue_as :scheduled_jobs def perform - Inbox.where(channel_type: 'Channel::Email').all.find_each(batch_size: 100) do |inbox| - ::Inboxes::FetchImapEmailsJob.perform_later(inbox.channel) if inbox.channel.imap_enabled + email_inboxes = Inbox.where(channel_type: 'Channel::Email') + email_inboxes.find_each(batch_size: 100) do |inbox| + ::Inboxes::FetchImapEmailsJob.perform_later(inbox.channel) if should_fetch_emails?(inbox) end end + + private + + def should_fetch_emails?(inbox) + inbox.channel.imap_enabled && !inbox.account.suspended? + end end diff --git a/spec/jobs/inboxes/fetch_imap_email_inboxes_job_spec.rb b/spec/jobs/inboxes/fetch_imap_email_inboxes_job_spec.rb index ae4f540d4..18685a649 100644 --- a/spec/jobs/inboxes/fetch_imap_email_inboxes_job_spec.rb +++ b/spec/jobs/inboxes/fetch_imap_email_inboxes_job_spec.rb @@ -2,11 +2,19 @@ require 'rails_helper' RSpec.describe Inboxes::FetchImapEmailInboxesJob do let(:account) { create(:account) } + let(:suspended_account) { create(:account, status: 'suspended') } + let(:imap_email_channel) do - create(:channel_email, imap_enabled: true, imap_address: 'imap.gmail.com', imap_port: 993, imap_login: 'imap@gmail.com', - imap_password: 'password', account: account) + create(:channel_email, imap_enabled: true, account: account) + end + + let(:imap_email_channel_suspended) do + create(:channel_email, imap_enabled: true, account: suspended_account) + end + + let(:disabled_imap_channel) do + create(:channel_email, imap_enabled: false, account: account) end - let(:email_inbox) { create(:inbox, channel: imap_email_channel, account: account) } it 'enqueues the job' do expect { described_class.perform_later }.to have_enqueued_job(described_class) @@ -14,9 +22,26 @@ RSpec.describe Inboxes::FetchImapEmailInboxesJob do end context 'when called' do - it 'fetch all the email channels' do + it 'fetches emails only for active accounts with imap enabled' do + # Should call perform_later only once for the active, imap-enabled inbox expect(Inboxes::FetchImapEmailsJob).to receive(:perform_later).with(imap_email_channel).once + # Should not call for suspended account or disabled IMAP channels + expect(Inboxes::FetchImapEmailsJob).not_to receive(:perform_later).with(imap_email_channel_suspended) + expect(Inboxes::FetchImapEmailsJob).not_to receive(:perform_later).with(disabled_imap_channel) + + described_class.perform_now + end + + it 'skips suspended accounts' do + expect(Inboxes::FetchImapEmailsJob).not_to receive(:perform_later).with(imap_email_channel_suspended) + + described_class.perform_now + end + + it 'skips disabled imap channels' do + expect(Inboxes::FetchImapEmailsJob).not_to receive(:perform_later).with(disabled_imap_channel) + described_class.perform_now end end From 7e1458fd32f8c24e4da84097f6510b120e22907b Mon Sep 17 00:00:00 2001 From: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> Date: Thu, 6 Mar 2025 10:53:02 +0530 Subject: [PATCH 3/3] fix: Issue when saving hotkeys (#11026) # Pull Request Template ## Description This PR fixes an issue when saving send message button hotkeys, where a TypeError occurs: `this.updateUISettings is not a function`. This issue arises after merging this PR https://github.com/chatwoot/chatwoot/pull/10974 Fixes https://chatwoot-p3.sentry.io/issues/6339976939/events/ca9946f92cb74428a72f1f74976a56a3/ ## Type of change - [x] Bug fix (non-breaking change which fixes an issue) ## Checklist: - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my code - [ ] I have commented on my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] Any dependent changes have been merged and published in downstream modules --- .../dashboard/routes/dashboard/settings/profile/Index.vue | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/javascript/dashboard/routes/dashboard/settings/profile/Index.vue b/app/javascript/dashboard/routes/dashboard/settings/profile/Index.vue index 85204627a..45a060e05 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/profile/Index.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/profile/Index.vue @@ -39,13 +39,14 @@ export default { }, mixins: [globalConfigMixin], setup() { - const { isEditorHotKeyEnabled } = useUISettings(); + const { isEditorHotKeyEnabled, updateUISettings } = useUISettings(); const { currentFontSize, updateFontSize } = useFontSize(); return { currentFontSize, updateFontSize, isEditorHotKeyEnabled, + updateUISettings, }; }, data() {