Skip to content
This repository was archived by the owner on Jul 22, 2025. It is now read-only.

Commit 442530a

Browse files
authored
UX: Show error and ability to try again when no suggestions (#1426)
## 🔍 Overview When the title suggestions return no suggestions, there is no indication in the UI. In the tag suggester we show a toast when there aren't any suggestions but the request was a success. In this update we make a similar UI indication with a toast for both category and title suggestions. Additionally, for all suggestions we add a "Try again" button to the toast so that suggestions can be generated again if the results yield nothing the first time.
1 parent a907bc8 commit 442530a

File tree

5 files changed

+102
-21
lines changed

5 files changed

+102
-21
lines changed

assets/javascripts/discourse/components/suggestion-menus/ai-category-suggester.gjs

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ import { ajax } from "discourse/lib/ajax";
1111
import { popupAjaxError } from "discourse/lib/ajax-error";
1212
import { i18n } from "discourse-i18n";
1313
import DMenu from "float-kit/components/d-menu";
14-
import { MIN_CHARACTER_COUNT } from "../../lib/ai-helper-suggestions";
14+
import {
15+
MIN_CHARACTER_COUNT,
16+
showSuggestionsError,
17+
} from "../../lib/ai-helper-suggestions";
1518

1619
export default class AiCategorySuggester extends Component {
1720
@service siteSettings;
@@ -40,9 +43,20 @@ export default class AiCategorySuggester extends Component {
4043
return this.siteSettings.ai_embeddings_enabled && showTrigger;
4144
}
4245

46+
get showDropdown() {
47+
if (this.suggestions?.length <= 0) {
48+
this.dMenu.close();
49+
}
50+
return !this.loading && this.suggestions?.length > 0;
51+
}
52+
4353
@action
4454
async loadSuggestions() {
45-
if (this.suggestions && !this.dMenu.expanded) {
55+
if (
56+
this.suggestions &&
57+
this.suggestions?.length > 0 &&
58+
!this.dMenu.expanded
59+
) {
4660
return this.suggestions;
4761
}
4862

@@ -65,7 +79,13 @@ export default class AiCategorySuggester extends Component {
6579
data,
6680
}
6781
);
82+
6883
this.suggestions = assistant;
84+
85+
if (this.suggestions?.length <= 0) {
86+
showSuggestionsError(this, this.loadSuggestions.bind(this));
87+
return;
88+
}
6989
} catch (error) {
7090
popupAjaxError(error);
7191
} finally {
@@ -100,7 +120,13 @@ export default class AiCategorySuggester extends Component {
100120

101121
@action
102122
onClose() {
103-
this.triggerIcon = "discourse-sparkles";
123+
if (this.suggestions?.length > 0) {
124+
// If all suggestions have been used,
125+
// re-triggering when no suggestions present
126+
// will cause computation issues with
127+
// setting the icon, so we prevent it
128+
this.triggerIcon = "discourse-sparkles";
129+
}
104130
}
105131

106132
<template>
@@ -121,7 +147,7 @@ export default class AiCategorySuggester extends Component {
121147
{{on "click" this.loadSuggestions}}
122148
>
123149
<:content>
124-
{{#unless this.loading}}
150+
{{#if this.showDropdown}}
125151
<DropdownMenu as |dropdown|>
126152
{{#each this.suggestions as |suggestion index|}}
127153
<dropdown.item>
@@ -141,7 +167,7 @@ export default class AiCategorySuggester extends Component {
141167
</dropdown.item>
142168
{{/each}}
143169
</DropdownMenu>
144-
{{/unless}}
170+
{{/if}}
145171
</:content>
146172
</DMenu>
147173
{{/if}}

assets/javascripts/discourse/components/suggestion-menus/ai-tag-suggester.gjs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ import { ajax } from "discourse/lib/ajax";
1111
import { popupAjaxError } from "discourse/lib/ajax-error";
1212
import { i18n } from "discourse-i18n";
1313
import DMenu from "float-kit/components/d-menu";
14-
import { MIN_CHARACTER_COUNT } from "../../lib/ai-helper-suggestions";
14+
import {
15+
MIN_CHARACTER_COUNT,
16+
showSuggestionsError,
17+
} from "../../lib/ai-helper-suggestions";
1518

1619
export default class AiTagSuggester extends Component {
1720
@service siteSettings;
@@ -79,6 +82,7 @@ export default class AiTagSuggester extends Component {
7982
method: "POST",
8083
data,
8184
});
85+
8286
this.suggestions = assistant;
8387

8488
const model = this.args.composer
@@ -92,15 +96,7 @@ export default class AiTagSuggester extends Component {
9296
}
9397

9498
if (this.suggestions?.length <= 0) {
95-
this.toasts.error({
96-
class: "ai-suggestion-error",
97-
duration: 3000,
98-
data: {
99-
message: i18n(
100-
"discourse_ai.ai_helper.suggest_errors.no_suggestions"
101-
),
102-
},
103-
});
99+
showSuggestionsError(this, this.loadSuggestions.bind(this));
104100
return;
105101
}
106102
} catch (error) {

assets/javascripts/discourse/components/suggestion-menus/ai-title-suggester.gjs

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ import { ajax } from "discourse/lib/ajax";
99
import { popupAjaxError } from "discourse/lib/ajax-error";
1010
import { i18n } from "discourse-i18n";
1111
import DMenu from "float-kit/components/d-menu";
12-
import { MIN_CHARACTER_COUNT } from "../../lib/ai-helper-suggestions";
12+
import {
13+
MIN_CHARACTER_COUNT,
14+
showSuggestionsError,
15+
} from "../../lib/ai-helper-suggestions";
1316

1417
export default class AiTitleSuggester extends Component {
1518
@tracked loading = false;
@@ -46,9 +49,20 @@ export default class AiTitleSuggester extends Component {
4649
return showTrigger;
4750
}
4851

52+
get showDropdown() {
53+
if (this.suggestions?.length <= 0) {
54+
this.dMenu.close();
55+
}
56+
return !this.loading && this.suggestions?.length > 0;
57+
}
58+
4959
@action
5060
async loadSuggestions() {
51-
if (this.suggestions && !this.dMenu.expanded) {
61+
if (
62+
this.suggestions &&
63+
this.suggestions?.length > 0 &&
64+
!this.dMenu.expanded
65+
) {
5266
return this.suggestions;
5367
}
5468

@@ -70,7 +84,13 @@ export default class AiTitleSuggester extends Component {
7084
data,
7185
}
7286
);
87+
7388
this.suggestions = suggestions;
89+
90+
if (this.suggestions?.length <= 0) {
91+
showSuggestionsError(this, this.loadSuggestions.bind(this));
92+
return;
93+
}
7494
} catch (error) {
7595
popupAjaxError(error);
7696
} finally {
@@ -99,7 +119,13 @@ export default class AiTitleSuggester extends Component {
99119

100120
@action
101121
onClose() {
102-
this.triggerIcon = "discourse-sparkles";
122+
if (this.suggestions?.length > 0) {
123+
// If all suggestions have been used,
124+
// re-triggering when no suggestions present
125+
// will cause computation issues with
126+
// setting the icon, so we prevent it
127+
this.triggerIcon = "discourse-sparkles";
128+
}
103129
}
104130

105131
<template>
@@ -120,7 +146,7 @@ export default class AiTitleSuggester extends Component {
120146
{{on "click" this.loadSuggestions}}
121147
>
122148
<:content>
123-
{{#unless this.loading}}
149+
{{#if this.showDropdown}}
124150
<DropdownMenu as |dropdown|>
125151
{{#each this.suggestions as |suggestion index|}}
126152
<dropdown.item>
@@ -135,7 +161,7 @@ export default class AiTitleSuggester extends Component {
135161
</dropdown.item>
136162
{{/each}}
137163
</DropdownMenu>
138-
{{/unless}}
164+
{{/if}}
139165
</:content>
140166
</DMenu>
141167
{{/if}}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,34 @@
1+
import { getOwner } from "@ember/application";
2+
import { later } from "@ember/runloop";
3+
import { i18n } from "discourse-i18n";
4+
15
export const MIN_CHARACTER_COUNT = 40;
6+
7+
export function showSuggestionsError(context, reloadFn) {
8+
const toasts = getOwner(context).lookup("service:toasts");
9+
10+
toasts.error({
11+
class: "ai-suggestion-error",
12+
duration: "long",
13+
showProgressBar: true,
14+
data: {
15+
message: i18n("discourse_ai.ai_helper.suggest_errors.no_suggestions"),
16+
actions: [
17+
{
18+
label: i18n("discourse_ai.ai_helper.context_menu.regen"),
19+
icon: "rotate",
20+
class: "btn btn-small",
21+
action: async (toast) => {
22+
toast.close();
23+
24+
await reloadFn();
25+
26+
if (context.dMenu?.show && context.suggestions?.length > 0) {
27+
later(() => context.dMenu.show(), 50);
28+
}
29+
},
30+
},
31+
],
32+
},
33+
});
34+
}

config/locales/client.en.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -599,7 +599,7 @@ en:
599599
trigger: "Ask AI"
600600
loading: "AI is generating"
601601
cancel: "Cancel"
602-
regen: "Try Again"
602+
regen: "Try again"
603603
confirm: "Confirm"
604604
discard: "Discard"
605605
changes: "Suggested edits"

0 commit comments

Comments
 (0)