diff --git a/plugins/chat/app/models/chat_message.rb b/plugins/chat/app/models/chat_message.rb index 2c07386bb3..145144ad79 100644 --- a/plugins/chat/app/models/chat_message.rb +++ b/plugins/chat/app/models/chat_message.rb @@ -90,7 +90,7 @@ class ChatMessage < ActiveRecord::Base return uploads.first.original_filename if cooked.blank? && uploads.present? # this may return blank for some complex things like quotes, that is acceptable - PrettyText.excerpt(cooked, 50, {}) + PrettyText.excerpt(cooked, 50, { text_entities: true }) end def cooked_for_excerpt diff --git a/plugins/chat/assets/javascripts/discourse/components/chat-message-actions-desktop.hbs b/plugins/chat/assets/javascripts/discourse/components/chat-message-actions-desktop.hbs index 7b328c671b..07d9d99fa3 100644 --- a/plugins/chat/assets/javascripts/discourse/components/chat-message-actions-desktop.hbs +++ b/plugins/chat/assets/javascripts/discourse/components/chat-message-actions-desktop.hbs @@ -42,6 +42,7 @@ @class="btn-flat chat-message-thread-btn" @action={{this.messageActions.showThread}} @icon="puzzle-piece" + @title="chat.threads.open" /> {{/if}} diff --git a/plugins/chat/assets/javascripts/discourse/components/chat-thread.hbs b/plugins/chat/assets/javascripts/discourse/components/chat-thread.hbs index fc639a71ce..7ae72eadba 100644 --- a/plugins/chat/assets/javascripts/discourse/components/chat-thread.hbs +++ b/plugins/chat/assets/javascripts/discourse/components/chat-thread.hbs @@ -1,6 +1,6 @@ -
+
-
+

{{this.title}}

diff --git a/plugins/chat/config/locales/client.en.yml b/plugins/chat/config/locales/client.en.yml index 056c18be9a..a72cfde032 100644 --- a/plugins/chat/config/locales/client.en.yml +++ b/plugins/chat/config/locales/client.en.yml @@ -67,7 +67,7 @@ en: channel_delete: title: "Delete Channel" instructions: "

Deletes the %{name} channel and chat history. All messages and related data, such as reactions and uploads, will be permanently deleted. If you want to preserve the channel history and decomission it, you may want to archive the channel instead.

-

Are you sure you want to permanently delete the channel? To confirm, type the name of the channel in the box below.

" +

Are you sure you want to permanently delete the channel? To confirm, type the name of the channel in the box below.

" confirm: "I understand the consequences, delete the channel" confirm_channel_name: "Enter channel name" process_started: "The process to delete the channel has started. This modal will close shortly, you will no longer see the deleted channel anywhere." @@ -444,6 +444,7 @@ en: threads: op_said: "OP said:" + open: "Open Thread" draft_channel_screen: header: "New Message" diff --git a/plugins/chat/spec/plugin_helper.rb b/plugins/chat/spec/plugin_helper.rb index 33657da1fc..f7e5c00155 100644 --- a/plugins/chat/spec/plugin_helper.rb +++ b/plugins/chat/spec/plugin_helper.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require "faker" + module ChatSystemHelpers def chat_system_bootstrap(user = Fabricate(:admin), channels_for_membership = []) # ensures we have one valid registered admin/user @@ -20,6 +22,31 @@ module ChatSystemHelpers # this is reset after each test Bookmark.register_bookmarkable(ChatMessageBookmarkable) end + + def chat_thread_chain_bootstrap(channel:, users:, messages_count: 4) + last_user = nil + last_message = nil + + messages_count.times do |i| + in_reply_to = i.zero? ? nil : last_message.id + thread_id = i.zero? ? nil : last_message.thread_id + last_user = last_user.present? ? (users - [last_user]).sample : users.sample + creator = + Chat::ChatMessageCreator.new( + chat_channel: channel, + in_reply_to_id: in_reply_to, + thread_id: thread_id, + user: last_user, + content: Faker::Lorem.paragraph, + ) + creator.create + + raise creator.error if creator.error + last_message = creator.chat_message + end + + last_message.thread + end end RSpec.configure { |config| config.include ChatSystemHelpers, type: :system } diff --git a/plugins/chat/spec/system/page_objects/chat/chat_channel.rb b/plugins/chat/spec/system/page_objects/chat/chat_channel.rb index 715c2a3d2e..ad7d3bb043 100644 --- a/plugins/chat/spec/system/page_objects/chat/chat_channel.rb +++ b/plugins/chat/spec/system/page_objects/chat/chat_channel.rb @@ -51,6 +51,11 @@ module PageObjects find("[data-value='flag']").click end + def open_message_thread(message) + hover_message(message) + find(".chat-message-thread-btn").click + end + def select_message(message) hover_message(message) click_more_buttons(message) diff --git a/plugins/chat/spec/system/page_objects/chat/chat_side_panel.rb b/plugins/chat/spec/system/page_objects/chat/chat_side_panel.rb new file mode 100644 index 0000000000..01dfb1f2da --- /dev/null +++ b/plugins/chat/spec/system/page_objects/chat/chat_side_panel.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module PageObjects + module Pages + class ChatSidePanel < PageObjects::Pages::Base + def has_open_thread?(thread) + has_css?(".chat-side-panel .chat-thread[data-id='#{thread.id}']") + end + end + end +end diff --git a/plugins/chat/spec/system/page_objects/chat/chat_thread.rb b/plugins/chat/spec/system/page_objects/chat/chat_thread.rb new file mode 100644 index 0000000000..7835e0721e --- /dev/null +++ b/plugins/chat/spec/system/page_objects/chat/chat_thread.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module PageObjects + module Pages + class ChatThread < PageObjects::Pages::Base + def has_header_content?(content) + find(".chat-thread__header").has_content?(content) + end + end + end +end diff --git a/plugins/chat/spec/system/single_thread_spec.rb b/plugins/chat/spec/system/single_thread_spec.rb new file mode 100644 index 0000000000..6a3a774469 --- /dev/null +++ b/plugins/chat/spec/system/single_thread_spec.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +describe "Single thread in side panel", type: :system, js: true do + fab!(:current_user) { Fabricate(:user) } + + let(:chat_page) { PageObjects::Pages::Chat.new } + let(:channel_page) { PageObjects::Pages::ChatChannel.new } + let(:side_panel) { PageObjects::Pages::ChatSidePanel.new } + let(:open_thread) { PageObjects::Pages::ChatThread.new } + + before do + chat_system_bootstrap(current_user, [channel]) + sign_in(current_user) + end + + context "when enable_experimental_chat_threaded_discussions is disabled" do + fab!(:channel) { Fabricate(:chat_channel) } + before { SiteSetting.enable_experimental_chat_threaded_discussions = false } + + it "does not open the side panel for a single thread" do + thread = + chat_thread_chain_bootstrap(channel: channel, users: [current_user, Fabricate(:user)]) + chat_page.visit_channel(channel) + channel_page.hover_message(thread.original_message) + expect(page).not_to have_css(".chat-message-thread-btn") + end + end + + context "when threading_enabled is false for the channel" do + fab!(:channel) { Fabricate(:chat_channel) } + before do + SiteSetting.enable_experimental_chat_threaded_discussions = true + channel.update!(threading_enabled: false) + end + + it "does not open the side panel for a single thread" do + thread = + chat_thread_chain_bootstrap(channel: channel, users: [current_user, Fabricate(:user)]) + chat_page.visit_channel(channel) + channel_page.hover_message(thread.original_message) + expect(page).not_to have_css(".chat-message-thread-btn") + end + end + + context "when enable_experimental_chat_threaded_discussions is true and threading is enabled for the channel" do + fab!(:user_2) { Fabricate(:user) } + fab!(:channel) { Fabricate(:chat_channel, threading_enabled: true) } + fab!(:thread) { chat_thread_chain_bootstrap(channel: channel, users: [current_user, user_2]) } + + before { SiteSetting.enable_experimental_chat_threaded_discussions = true } + + it "opens the side panel for a single thread from the message actions menu" do + chat_page.visit_channel(channel) + channel_page.open_message_thread(thread.original_message) + expect(side_panel).to have_open_thread(thread) + end + + it "shows the excerpt of the thread original message" do + chat_page.visit_channel(channel) + channel_page.open_message_thread(thread.original_message) + expect(open_thread).to have_header_content(thread.original_message.excerpt) + end + end +end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index c822777e70..e526c685b9 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -283,13 +283,13 @@ RSpec.configure do |config| end Capybara.register_driver :selenium_chrome do |app| - Capybara::Selenium::Driver.new(app, browser: :chrome, capabilities: chrome_browser_options) + Capybara::Selenium::Driver.new(app, browser: :chrome, options: chrome_browser_options) end Capybara.register_driver :selenium_chrome_headless do |app| chrome_browser_options.add_argument("--headless") - Capybara::Selenium::Driver.new(app, browser: :chrome, capabilities: chrome_browser_options) + Capybara::Selenium::Driver.new(app, browser: :chrome, options: chrome_browser_options) end mobile_chrome_browser_options = @@ -304,20 +304,12 @@ RSpec.configure do |config| end Capybara.register_driver :selenium_mobile_chrome do |app| - Capybara::Selenium::Driver.new( - app, - browser: :chrome, - capabilities: mobile_chrome_browser_options, - ) + Capybara::Selenium::Driver.new(app, browser: :chrome, options: mobile_chrome_browser_options) end Capybara.register_driver :selenium_mobile_chrome_headless do |app| mobile_chrome_browser_options.add_argument("--headless") - Capybara::Selenium::Driver.new( - app, - browser: :chrome, - capabilities: mobile_chrome_browser_options, - ) + Capybara::Selenium::Driver.new(app, browser: :chrome, options: mobile_chrome_browser_options) end if ENV["ELEVATED_UPLOADS_ID"]