From da4b146171c68e3627e1f0267818f6c7e2619505 Mon Sep 17 00:00:00 2001 From: Matt Lindsey Date: Tue, 10 Dec 2024 16:32:47 -0500 Subject: [PATCH] Add basic text search of conversations (#576) Co-authored-by: Keith Schacht --- app/controllers/conversations_controller.rb | 10 ++-- app/controllers/messages_controller.rb | 6 --- app/javascript/stimulus/search_controller.js | 37 +++++++++++++ app/models/conversation.rb | 10 +++- app/views/conversations/index.html.erb | 57 ++++++++++++++++++++ app/views/messages/_nav_column.html.erb | 21 ++------ config/routes.rb | 2 +- test/models/conversation_test.rb | 34 ++++++++++++ 8 files changed, 147 insertions(+), 30 deletions(-) create mode 100644 app/javascript/stimulus/search_controller.js create mode 100644 app/views/conversations/index.html.erb diff --git a/app/controllers/conversations_controller.rb b/app/controllers/conversations_controller.rb index aeef68680..a11402fe1 100644 --- a/app/controllers/conversations_controller.rb +++ b/app/controllers/conversations_controller.rb @@ -1,8 +1,12 @@ class ConversationsController < ApplicationController before_action :set_conversation, only: [:show, :edit, :update, :destroy] - before_action :set_nav_conversations before_action :set_nav_assistants + def index + @query = params[:query] + @nav_conversations = Conversation.grouped_by_increasing_time_interval_for_user(Current.user, @query) + end + def show end @@ -28,10 +32,6 @@ def destroy private - def set_nav_conversations - @nav_conversations = Conversation.grouped_by_increasing_time_interval_for_user(Current.user) - end - def set_nav_assistants @nav_assistants = Current.user.assistants.ordered end diff --git a/app/controllers/messages_controller.rb b/app/controllers/messages_controller.rb index 01590b89f..8aff33231 100644 --- a/app/controllers/messages_controller.rb +++ b/app/controllers/messages_controller.rb @@ -6,7 +6,6 @@ class MessagesController < ApplicationController before_action :set_conversation, only: [:index] before_action :set_assistant, only: [:index, :new, :edit, :create] before_action :set_message, only: [:show, :edit, :update] - before_action :set_nav_conversations, only: [:index, :new] before_action :set_nav_assistants, only: [:index, :new] before_action :set_conversation_starters, only: [:new] @@ -46,7 +45,6 @@ def create redirect_to conversation_messages_path(@message.conversation, version: @message.version), status: :see_other else # what's the right flow for a failed message create? it's not this, but hacking it so tests pass until we have a plan - set_nav_conversations set_nav_assistants @new_message = @assistant.messages.new @@ -82,10 +80,6 @@ def set_message redirect_to root_url, status: :unauthorized if @message.conversation.user != Current.user end - def set_nav_conversations - @nav_conversations = Conversation.grouped_by_increasing_time_interval_for_user(Current.user) - end - def set_nav_assistants @nav_assistants = Current.user.assistants.ordered end diff --git a/app/javascript/stimulus/search_controller.js b/app/javascript/stimulus/search_controller.js new file mode 100644 index 000000000..65b58720d --- /dev/null +++ b/app/javascript/stimulus/search_controller.js @@ -0,0 +1,37 @@ +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + static targets = [ "input", "clear" ] + + inputTargetConnected() { + this.setSearchClearIcon() + } + + disconnect() { + clearTimeout(this.timeout) + } + + clear() { + this.inputTarget.value = "" + this.element.requestSubmit() + } + + unfocus() { + this.inputTarget.autofocus = false + } + + search() { + clearTimeout(this.timeout) + this.setSearchClearIcon() + this.timeout = setTimeout(() => { + this.element.requestSubmit() + }, 500) + } + + setSearchClearIcon() { + if (this.inputTarget.value.length > 0) + this.clearTarget.classList.remove("hidden") + else + this.clearTarget.classList.add("hidden") + } +} diff --git a/app/models/conversation.rb b/app/models/conversation.rb index 61106f911..af2245e3b 100644 --- a/app/models/conversation.rb +++ b/app/models/conversation.rb @@ -27,8 +27,14 @@ class Conversation < ApplicationRecord # "Last Month" => relation, # "Older" => relation # } - def self.grouped_by_increasing_time_interval_for_user(user) - nav_conversations = user.conversations.ordered + def self.grouped_by_increasing_time_interval_for_user(user, query = nil) + if query.blank? + nav_conversations = user.conversations.ordered + else + nav_conversations = user.conversations.joins(:messages).ordered.where("messages.content_text ILIKE ?", "%#{query}%"). + or(user.conversations.ordered.where("title ILIKE ?", "%#{query}%")). + select("DISTINCT conversations.*") + end keys = ["Today", "Yesterday", "This Week", "This Month", "Last Month", "Older"] values = [ diff --git a/app/views/conversations/index.html.erb b/app/views/conversations/index.html.erb new file mode 100644 index 000000000..951113dc7 --- /dev/null +++ b/app/views/conversations/index.html.erb @@ -0,0 +1,57 @@ + + + +
+ + > + <% @nav_conversations.each do |named_time_span, conversations| %> +
+ <%= named_time_span %> +
+ + <%= render conversations %> + <% end %> +
+
+
diff --git a/app/views/messages/_nav_column.html.erb b/app/views/messages/_nav_column.html.erb index 8b359a07e..19372969b 100644 --- a/app/views/messages/_nav_column.html.erb +++ b/app/views/messages/_nav_column.html.erb @@ -25,19 +25,8 @@ <% end %> -
- - > - <% @nav_conversations.each do |named_time_span, conversations| %> -
- <%= named_time_span %> -
- - <%= render conversations %> - <% end %> -
-
+ diff --git a/config/routes.rb b/config/routes.rb index e954284bd..73386abb5 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -7,7 +7,7 @@ resources :messages, only: [:new, :create, :edit] end - resources :conversations, only: [:show, :edit, :update, :destroy] do + resources :conversations, only: [:index, :show, :edit, :update, :destroy] do resources :messages, only: [:index] end diff --git a/test/models/conversation_test.rb b/test/models/conversation_test.rb index f382e7c79..58a38ac94 100644 --- a/test/models/conversation_test.rb +++ b/test/models/conversation_test.rb @@ -125,4 +125,38 @@ class ConversationTest < ActiveSupport::TestCase assert_equal 3, grouped_conversations["Older"].count end end + + test "#grouped_by_increasing_time_interval_for_user with a query returning a single conversation title" do + user = users(:keith) + query = "Ruby" + + grouped_conversations = Conversation.grouped_by_increasing_time_interval_for_user(user, query).values.flatten + + assert_equal 1, grouped_conversations.count + assert_equal conversations(:ruby_version), grouped_conversations.first, "Should have returned this conversation based on title" + end + + test "#grouped_by_increasing_time_interval_for_user with a query returning a single conversation message" do + user = users(:keith) + query = "alive" + + grouped_conversations = Conversation.grouped_by_increasing_time_interval_for_user(user, query).values.flatten + + assert_equal 1, grouped_conversations.count + assert_equal conversations(:greeting), grouped_conversations.first, "Should have returned this conversation based on message content" + end + + test "#grouped_by_increasing_time_interval_for_user with a query returning matching conversation titles and a message" do + user = users(:keith) + query = "test" + + grouped_conversations = Conversation.grouped_by_increasing_time_interval_for_user(user, query).values.flatten + + assert_equal 3, grouped_conversations.count + assert_equal [ + conversations(:attachment).id, # matches title + conversations(:attachments).id, # matches title + conversations(:ruby_version).id # matches "latest" in messages + ].sort, grouped_conversations.map(&:id).sort, "Should have returned these conversations based on title and message content" + end end