FIX: clear uploads after successfully posting new PM (#1307)

This PR addresses a bug where uploads weren't being cleared after successfully posting a new private message in the AI bot conversations interface. Here's what the changes do:

## Main Fix:
- Makes the `prepareAndSubmitToBot()` method async and adds proper error handling
- Adds `this.uploads.clear()` after successful submission to clear all uploads
- Adds a test to verify that the "New Question" button properly resets the UI with no uploads

## Additional Improvements:
1. **Dynamic Character Length Validation**:
   - Uses `siteSettings.min_personal_message_post_length` instead of hardcoded 10 characters
   - Updates the error message to show the dynamic character count
   - Adds proper pluralization in the localization file for the error message

2. **Bug Fixes**:
   - Adds null checks with optional chaining (`link?.topic?.id`) in the sidebar code to prevent potential errors

3. **Code Organization**:
   - Moves error handling from the service to the controller for better separation of concerns
This commit is contained in:
Sam 2025-05-02 13:46:22 +10:00 committed by GitHub
parent 9196546f6f
commit 3800728d52
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 28 additions and 10 deletions

View File

@ -3,6 +3,7 @@ import Controller from "@ember/controller";
import { action } from "@ember/object"; import { action } from "@ember/object";
import { getOwner } from "@ember/owner"; import { getOwner } from "@ember/owner";
import { service } from "@ember/service"; import { service } from "@ember/service";
import { popupAjaxError } from "discourse/lib/ajax-error";
import UppyUpload from "discourse/lib/uppy/uppy-upload"; import UppyUpload from "discourse/lib/uppy/uppy-upload";
import UppyMediaOptimization from "discourse/lib/uppy-media-optimization-plugin"; import UppyMediaOptimization from "discourse/lib/uppy-media-optimization-plugin";
import { clipboardHelpers } from "discourse/lib/utilities"; import { clipboardHelpers } from "discourse/lib/utilities";
@ -172,10 +173,15 @@ export default class DiscourseAiBotConversations extends Controller {
} }
@action @action
prepareAndSubmitToBot() { async prepareAndSubmitToBot() {
// Pass uploads to the service before submitting // Pass uploads to the service before submitting
this.aiBotConversationsHiddenSubmit.uploads = this.uploads; this.aiBotConversationsHiddenSubmit.uploads = this.uploads;
this.aiBotConversationsHiddenSubmit.submitToBot(); try {
await this.aiBotConversationsHiddenSubmit.submitToBot();
this.uploads.clear();
} catch (error) {
popupAjaxError(error);
}
} }
_autoExpandTextarea() { _autoExpandTextarea() {

View File

@ -3,7 +3,6 @@ import { next } from "@ember/runloop";
import Service, { service } from "@ember/service"; import Service, { service } from "@ember/service";
import { tracked } from "@ember-compat/tracked-built-ins"; import { tracked } from "@ember-compat/tracked-built-ins";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import { popupAjaxError } from "discourse/lib/ajax-error";
import { getUploadMarkdown } from "discourse/lib/uploads"; import { getUploadMarkdown } from "discourse/lib/uploads";
import { i18n } from "discourse-i18n"; import { i18n } from "discourse-i18n";
@ -13,6 +12,7 @@ export default class AiBotConversationsHiddenSubmit extends Service {
@service composer; @service composer;
@service dialog; @service dialog;
@service router; @service router;
@service siteSettings;
@tracked loading = false; @tracked loading = false;
@ -33,10 +33,14 @@ export default class AiBotConversationsHiddenSubmit extends Service {
@action @action
async submitToBot() { async submitToBot() {
if (this.inputValue.length < 10) { if (
this.inputValue.length <
this.siteSettings.min_personal_message_post_length
) {
return this.dialog.alert({ return this.dialog.alert({
message: i18n( message: i18n(
"discourse_ai.ai_bot.conversations.min_input_length_message" "discourse_ai.ai_bot.conversations.min_input_length_message",
{ count: this.siteSettings.min_personal_message_post_length }
), ),
didConfirm: () => this.focusInput(), didConfirm: () => this.focusInput(),
didCancel: () => this.focusInput(), didCancel: () => this.focusInput(),
@ -89,8 +93,6 @@ export default class AiBotConversationsHiddenSubmit extends Service {
}); });
this.router.transitionTo(response.post_url); this.router.transitionTo(response.post_url);
} catch (e) {
popupAjaxError(e);
} finally { } finally {
this.loading = false; this.loading = false;
} }

View File

@ -319,7 +319,7 @@ export default {
// force Glimmer to re-render that one link // force Glimmer to re-render that one link
this.links = this.links.map((link) => this.links = this.links.map((link) =>
link.topic.id === topic.id link?.topic?.id === topic.id
? new AiConversationLink(topic) ? new AiConversationLink(topic)
: link : link
); );

View File

@ -726,7 +726,9 @@ en:
disclaimer: "Generative AI can make mistakes. Verify important information." disclaimer: "Generative AI can make mistakes. Verify important information."
placeholder: "Ask a question..." placeholder: "Ask a question..."
new: "New Question" new: "New Question"
min_input_length_message: "Message must be longer than 10 characters" min_input_length_message:
one: "Message must be 1 character or longer"
other: "Message must be %{count} characters or longer"
messages_sidebar_title: "Conversations" messages_sidebar_title: "Conversations"
today: "Today" today: "Today"
last_7_days: "Last 7 days" last_7_days: "Last 7 days"

View File

@ -131,6 +131,10 @@ RSpec.describe "AI Bot - Homepage", type: :system do
expect(topic_page).to have_content("Here are two image attachments") expect(topic_page).to have_content("Here are two image attachments")
expect(page).to have_css(".cooked img", count: 2) expect(page).to have_css(".cooked img", count: 2)
end end
find(".ai-new-question-button").click
expect(ai_pm_homepage).to have_homepage
expect(page).to have_no_css(".ai-bot-upload")
end end
it "allows removing an upload before submission" do it "allows removing an upload before submission" do

View File

@ -20,7 +20,11 @@ module PageObjects
def has_too_short_dialog? def has_too_short_dialog?
page.find( page.find(
".dialog-content", ".dialog-content",
text: I18n.t("js.discourse_ai.ai_bot.conversations.min_input_length_message"), text:
I18n.t(
"js.discourse_ai.ai_bot.conversations.min_input_length_message",
count: SiteSetting.min_personal_message_post_length,
),
) )
end end