From 1e32416eaaa08c5e395f4ec5ec058de87dac46ff Mon Sep 17 00:00:00 2001 From: Mark VanLandingham Date: Wed, 30 Apr 2025 11:33:41 -0500 Subject: [PATCH] UX: Empty state for AI conversations sidebar & btn changes (#1297) This commit adds an empty state when the user doesn't have any PM history. It ALSO retains the new conversation button in the sidebar so it no longer jumps. The button is disabled, icon, and text are all updated. --- .../components/ai-bot-sidebar-empty-state.gjs | 7 +++++++ .../ai-bot-sidebar-new-conversation.gjs | 9 ++++---- .../discourse-ai-bot-conversations.gjs | 1 + .../initializers/ai-conversations-sidebar.js | 5 +++++ config/locales/client.en.yml | 1 + spec/system/ai_bot/homepage_spec.rb | 21 ++++++++++++------- .../page_objects/components/ai_pm_homepage.rb | 12 +++++++++++ 7 files changed, 44 insertions(+), 12 deletions(-) create mode 100644 assets/javascripts/discourse/components/ai-bot-sidebar-empty-state.gjs diff --git a/assets/javascripts/discourse/components/ai-bot-sidebar-empty-state.gjs b/assets/javascripts/discourse/components/ai-bot-sidebar-empty-state.gjs new file mode 100644 index 00000000..9a4c13a7 --- /dev/null +++ b/assets/javascripts/discourse/components/ai-bot-sidebar-empty-state.gjs @@ -0,0 +1,7 @@ +import { i18n } from "discourse-i18n"; + + diff --git a/assets/javascripts/discourse/components/ai-bot-sidebar-new-conversation.gjs b/assets/javascripts/discourse/components/ai-bot-sidebar-new-conversation.gjs index e4c4d323..777ea34a 100644 --- a/assets/javascripts/discourse/components/ai-bot-sidebar-new-conversation.gjs +++ b/assets/javascripts/discourse/components/ai-bot-sidebar-new-conversation.gjs @@ -9,15 +9,14 @@ export default class AiBotSidebarNewConversation extends Component { @service sidebarState; get shouldRender() { - return ( - this.router.currentRouteName !== "discourse-ai-bot-conversations" && - this.sidebarState.isCurrentPanel(AI_CONVERSATIONS_PANEL) - ); + return this.sidebarState.isCurrentPanel(AI_CONVERSATIONS_PANEL); } @action routeTo() { - this.router.transitionTo("/discourse-ai/ai-bot/conversations"); + if (this.router.currentRouteName !== "discourse-ai-bot-conversations") { + this.router.transitionTo("/discourse-ai/ai-bot/conversations"); + } this.args.outletArgs?.toggleNavigationMenu?.(); } diff --git a/assets/javascripts/discourse/templates/discourse-ai-bot-conversations.gjs b/assets/javascripts/discourse/templates/discourse-ai-bot-conversations.gjs index a8d32758..3027a780 100644 --- a/assets/javascripts/discourse/templates/discourse-ai-bot-conversations.gjs +++ b/assets/javascripts/discourse/templates/discourse-ai-bot-conversations.gjs @@ -31,6 +31,7 @@ export default RouteTemplate( {{on "input" @controller.updateInputValue}} {{on "keydown" @controller.handleKeyDown}} id="ai-bot-conversations-input" + autofocus="true" placeholder={{i18n "discourse_ai.ai_bot.conversations.placeholder"}} minlength="10" disabled={{@controller.loading}} diff --git a/assets/javascripts/initializers/ai-conversations-sidebar.js b/assets/javascripts/initializers/ai-conversations-sidebar.js index d4e454d6..4040632d 100644 --- a/assets/javascripts/initializers/ai-conversations-sidebar.js +++ b/assets/javascripts/initializers/ai-conversations-sidebar.js @@ -6,6 +6,7 @@ import { bind } from "discourse/lib/decorators"; import { autoUpdatingRelativeAge } from "discourse/lib/formatter"; import { withPluginApi } from "discourse/lib/plugin-api"; import { i18n } from "discourse-i18n"; +import AiBotSidebarEmptyState from "../discourse/components/ai-bot-sidebar-empty-state"; import AiBotSidebarNewConversation from "../discourse/components/ai-bot-sidebar-new-conversation"; import { AI_CONVERSATIONS_PANEL } from "../discourse/services/ai-conversations-sidebar-manager"; @@ -121,6 +122,10 @@ export default { return "ai-conversations-history"; } + get emptyStateComponent() { + return AiBotSidebarEmptyState; + } + get text() { return i18n( "discourse_ai.ai_bot.conversations.messages_sidebar_title" diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 8e02e480..d153800c 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -673,6 +673,7 @@ en: share: "Copy AI conversation" conversation_shared: "Conversation copied" debug_ai: "View raw AI request and response" + sidebar_empty: "Bot conversation history will appear here." debug_ai_modal: title: "View AI interaction" copy_request: "Copy request" diff --git a/spec/system/ai_bot/homepage_spec.rb b/spec/system/ai_bot/homepage_spec.rb index 671b79c7..93dfb7ad 100644 --- a/spec/system/ai_bot/homepage_spec.rb +++ b/spec/system/ai_bot/homepage_spec.rb @@ -149,7 +149,6 @@ RSpec.describe "AI Bot - Homepage", type: :system do expect(sidebar).to have_section("ai-conversations-history") expect(sidebar).to have_section_link("Today") expect(sidebar).to have_section_link(pm.title) - expect(sidebar).to have_no_css("button.ai-new-question-button") end it "displays last_7_days label in the sidebar" do @@ -204,16 +203,18 @@ RSpec.describe "AI Bot - Homepage", type: :system do expect(header).to have_icon_in_bot_button(icon: "robot") end - it "displays sidebar and 'new question' on the topic page" do + it "displays 'new question' button on homepage and topic page" do topic_page.visit_topic(pm) - expect(sidebar).to be_visible - expect(sidebar).to have_css("button.ai-new-question-button") + expect(ai_pm_homepage).to have_new_question_button + + ai_pm_homepage.visit + expect(ai_pm_homepage).to have_new_question_button end it "redirect to the homepage when 'new question' is clicked" do topic_page.visit_topic(pm) expect(sidebar).to be_visible - sidebar.find("button.ai-new-question-button").click + ai_pm_homepage.click_new_question_button expect(ai_pm_homepage).to have_homepage end @@ -232,6 +233,7 @@ RSpec.describe "AI Bot - Homepage", type: :system do Fabricate(:post, topic: pm, user: user_2, post_number: 4) Fabricate(:topic_allowed_user, topic: pm, user: user_2) sign_in(user_2) + topic_page.visit_topic(pm) expect(sidebar).to be_visible @@ -244,13 +246,18 @@ RSpec.describe "AI Bot - Homepage", type: :system do Fabricate(:post, topic: pm, user: user_2, post_number: 4) Fabricate(:topic_allowed_user, topic: pm, user: user_2) sign_in(user_2) - visit "/" header.click_bot_button expect(ai_pm_homepage).to have_homepage expect(sidebar).to have_no_section_link(pm.title) end + it "renders empty state in sidebar with no bot PM history" do + sign_in(user_2) + ai_pm_homepage.visit + expect(ai_pm_homepage).to have_empty_state + end + it "Allows choosing persona and LLM" do ai_pm_homepage.visit @@ -325,7 +332,7 @@ RSpec.describe "AI Bot - Homepage", type: :system do it "displays the new question button in the menu when viewing a PM" do ai_pm_homepage.visit header_dropdown.open - expect(ai_pm_homepage).to have_no_new_question_button + expect(ai_pm_homepage).to have_new_question_button topic_page.visit_topic(pm) header_dropdown.open diff --git a/spec/system/page_objects/components/ai_pm_homepage.rb b/spec/system/page_objects/components/ai_pm_homepage.rb index de605a8e..f850ebcd 100644 --- a/spec/system/page_objects/components/ai_pm_homepage.rb +++ b/spec/system/page_objects/components/ai_pm_homepage.rb @@ -36,10 +36,22 @@ module PageObjects page.has_no_css?(".ai-new-question-button") end + def has_new_question_button? + sidebar = PageObjects::Components::NavigationMenu::Sidebar.new + sidebar.has_css?( + "button.ai-new-question-button", + text: I18n.t("js.discourse_ai.ai_bot.conversations.new"), + ) + end + def click_new_question_button page.find(".ai-new-question-button").click end + def has_empty_state? + page.has_css?(".ai-bot-sidebar-empty-state") + end + def click_fist_sidebar_conversation page.find( ".sidebar-section[data-section-name='ai-conversations-history'] a.sidebar-section-link:not(.date-heading)",