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

Commit 00ecf75

Browse files
committed
DEV: Add suggestion buttons to edit topic area
Requires new outlets
1 parent c95231d commit 00ecf75

File tree

7 files changed

+161
-22
lines changed

7 files changed

+161
-22
lines changed

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

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,26 @@ export default class AiCategorySuggester extends Component {
1919
@tracked suggestions = null;
2020
@tracked untriggers = [];
2121
@tracked triggerIcon = "discourse-sparkles";
22+
@tracked content = null;
23+
@tracked topicContent = null;
24+
25+
constructor() {
26+
super(...arguments);
27+
if (!this.topicContent && this.args.composer?.reply === undefined) {
28+
this.fetchTopicContent();
29+
}
30+
}
31+
32+
async fetchTopicContent() {
33+
await ajax(`/t/${this.args.buffered.content.id}.json`).then(({post_stream}) => {
34+
this.topicContent = post_stream.posts[0].cooked;
35+
});
36+
}
2237

2338
get showSuggestionButton() {
2439
const composerFields = document.querySelector(".composer-fields");
25-
const showTrigger = this.args.composer.reply?.length > MIN_CHARACTER_COUNT;
40+
this.content = this.args.composer?.reply || this.topicContent;
41+
const showTrigger = this.content?.length > MIN_CHARACTER_COUNT;
2642

2743
if (composerFields) {
2844
if (showTrigger) {
@@ -49,7 +65,7 @@ export default class AiCategorySuggester extends Component {
4965
"/discourse-ai/ai-helper/suggest_category",
5066
{
5167
method: "POST",
52-
data: { text: this.args.composer.reply },
68+
data: { text: this.content },
5369
}
5470
);
5571
this.suggestions = assistant;
@@ -66,12 +82,17 @@ export default class AiCategorySuggester extends Component {
6682
@action
6783
applySuggestion(suggestion) {
6884
const composer = this.args.composer;
69-
if (!composer) {
70-
return;
85+
const buffered = this.args.buffered;
86+
87+
if (composer) {
88+
composer.set("categoryId", suggestion.id);
89+
}
90+
91+
if (buffered) {
92+
this.args.buffered.set("category_id", suggestion.id);
7193
}
7294

73-
composer.set("categoryId", suggestion.id);
74-
this.dMenu.close();
95+
return this.dMenu.close();
7596
}
7697

7798
@action

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

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,26 @@ export default class AiTagSuggester extends Component {
2020
@tracked suggestions = null;
2121
@tracked untriggers = [];
2222
@tracked triggerIcon = "discourse-sparkles";
23+
@tracked content = null;
24+
@tracked topicContent = null;
25+
26+
constructor() {
27+
super(...arguments);
28+
if (!this.topicContent && this.args.composer?.reply === undefined) {
29+
this.fetchTopicContent();
30+
}
31+
}
32+
33+
async fetchTopicContent() {
34+
await ajax(`/t/${this.args.buffered.content.id}.json`).then(({post_stream}) => {
35+
this.topicContent = post_stream.posts[0].cooked;
36+
});
37+
}
2338

2439
get showSuggestionButton() {
2540
const composerFields = document.querySelector(".composer-fields");
26-
const showTrigger = this.args.composer.reply?.length > MIN_CHARACTER_COUNT;
41+
this.content = this.args.composer?.reply || this.topicContent;
42+
const showTrigger = this.content?.length > MIN_CHARACTER_COUNT;
2743

2844
if (composerFields) {
2945
if (showTrigger) {
@@ -59,13 +75,13 @@ export default class AiTagSuggester extends Component {
5975
try {
6076
const { assistant } = await ajax("/discourse-ai/ai-helper/suggest_tags", {
6177
method: "POST",
62-
data: { text: this.args.composer.reply },
78+
data: { text: this.content},
6379
});
6480
this.suggestions = assistant;
65-
81+
const model = this.args.composer ? this.args.composer : this.args.buffered;
6682
if (this.#tagSelectorHasValues()) {
6783
this.suggestions = this.suggestions.filter(
68-
(s) => !this.args.composer.tags.includes(s.name)
84+
(s) => !mode.get("tags").includes(s.name)
6985
);
7086
}
7187

@@ -104,19 +120,19 @@ export default class AiTagSuggester extends Component {
104120
@action
105121
applySuggestion(suggestion) {
106122
const maxTags = this.siteSettings.max_tags_per_topic;
107-
const composer = this.args.composer;
108-
if (!composer) {
123+
const model = this.args.composer ? this.args.composer : this.args.buffered;
124+
if (!model) {
109125
return;
110126
}
111127

112-
if (!composer.tags) {
113-
composer.set("tags", [suggestion.name]);
128+
const tags = model.get("tags");
129+
130+
if (!tags) {
131+
model.set("tags", [suggestion.name]);
114132
this.#removedAppliedTag(suggestion);
115133
return;
116134
}
117135

118-
const tags = composer.tags;
119-
120136
if (tags?.length >= maxTags) {
121137
return this.toasts.error({
122138
class: "ai-suggestion-error",
@@ -130,7 +146,7 @@ export default class AiTagSuggester extends Component {
130146
}
131147

132148
tags.push(suggestion.name);
133-
composer.set("tags", [...tags]);
149+
model.set("tags", [...tags]);
134150
suggestion.disabled = true;
135151
this.#removedAppliedTag(suggestion);
136152
}

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

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,29 @@ export default class AiTitleSuggester extends Component {
1616
@tracked suggestions = null;
1717
@tracked untriggers = [];
1818
@tracked triggerIcon = "discourse-sparkles";
19+
@tracked content = null;
20+
@tracked topicContent = null;
21+
22+
constructor() {
23+
super(...arguments);
24+
25+
if (!this.topicContent && this.args.composer?.reply === undefined) {
26+
this.fetchTopicContent();
27+
}
28+
}
29+
30+
async fetchTopicContent() {
31+
await ajax(`/t/${this.args.buffered.content.id}.json`).then(({post_stream}) => {
32+
this.topicContent = post_stream.posts[0].cooked;
33+
});
34+
}
1935

2036
get showSuggestionButton() {
2137
const composerFields = document.querySelector(".composer-fields");
22-
const showTrigger = this.args.composer.reply?.length > MIN_CHARACTER_COUNT;
38+
const editTopicTitleField = document.querySelector(".edit-topic-title");
39+
40+
this.content = this.args.composer?.reply || this.topicContent;
41+
const showTrigger = this.content?.length > MIN_CHARACTER_COUNT;
2342

2443
if (composerFields) {
2544
if (showTrigger) {
@@ -29,6 +48,14 @@ export default class AiTitleSuggester extends Component {
2948
}
3049
}
3150

51+
if (editTopicTitleField) {
52+
if (showTrigger) {
53+
editTopicTitleField.classList.add("showing-ai-suggestions");
54+
} else {
55+
editTopicTitleField.classList.remove("showing-ai-suggestions");
56+
}
57+
}
58+
3259
return showTrigger;
3360
}
3461

@@ -46,7 +73,7 @@ export default class AiTitleSuggester extends Component {
4673
"/discourse-ai/ai-helper/suggest_title",
4774
{
4875
method: "POST",
49-
data: { text: this.args.composer.reply },
76+
data: { text: this.content },
5077
}
5178
);
5279
this.suggestions = suggestions;
@@ -62,12 +89,12 @@ export default class AiTitleSuggester extends Component {
6289

6390
@action
6491
applySuggestion(suggestion) {
65-
const composer = this.args.composer;
66-
if (!composer) {
92+
const model = this.args.composer ? this.args.composer : this.args.buffered;
93+
if (!model) {
6794
return;
6895
}
6996

70-
composer.set("title", suggestion);
97+
model.set("title", suggestion);
7198
this.dMenu.close();
7299
}
73100

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import Component from "@glimmer/component";
2+
import AiCategorySuggester from "../../components/suggestion-menus/ai-category-suggester";
3+
import { showComposerAiHelper } from "../../lib/show-ai-helper";
4+
5+
export default class AiCategorySuggestion extends Component {
6+
static shouldRender(outletArgs, helper) {
7+
return showComposerAiHelper(
8+
outletArgs?.composer,
9+
helper.siteSettings,
10+
helper.currentUser,
11+
"suggestions"
12+
);
13+
}
14+
15+
<template>
16+
<AiCategorySuggester
17+
@buffered={{@outletArgs.buffered}}
18+
/>
19+
</template>
20+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import Component from "@glimmer/component";
2+
import AiTagSuggester from "../../components/suggestion-menus/ai-tag-suggester";
3+
import { showComposerAiHelper } from "../../lib/show-ai-helper";
4+
5+
export default class AiCategorySuggestion extends Component {
6+
static shouldRender(outletArgs, helper) {
7+
return showComposerAiHelper(
8+
outletArgs?.composer,
9+
helper.siteSettings,
10+
helper.currentUser,
11+
"suggestions"
12+
);
13+
}
14+
15+
<template>
16+
<AiTagSuggester
17+
@buffered={{@outletArgs.buffered}}
18+
/>
19+
</template>
20+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import Component from "@glimmer/component";
2+
import AiTitleSuggester from "../../components/suggestion-menus/ai-title-suggester";
3+
import { showComposerAiHelper } from "../../lib/show-ai-helper";
4+
5+
export default class AiTitleSuggestion extends Component {
6+
static shouldRender(outletArgs, helper) {
7+
return showComposerAiHelper(
8+
outletArgs?.composer,
9+
helper.siteSettings,
10+
helper.currentUser,
11+
"suggestions"
12+
);
13+
}
14+
15+
<template>
16+
<AiTitleSuggester @buffered={{@outletArgs.buffered}} />
17+
</template>
18+
}

assets/stylesheets/modules/ai-helper/common/ai-helper.scss

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,23 @@
257257
}
258258
}
259259

260+
.edit-topic-title {
261+
.suggestion-button {
262+
margin: 0;
263+
padding: 0.45rem;
264+
}
265+
}
266+
267+
#topic-title .edit-topic-title.showing-ai-suggestions {
268+
#edit-title {
269+
flex: 1 1 90%;
270+
}
271+
272+
.suggest-titles-button {
273+
padding: 0.5rem;
274+
}
275+
}
276+
260277
// Prevent suggestion button from wrapping
261278
#reply-control {
262279
.with-category .showing-ai-suggestions .category-input {

0 commit comments

Comments
 (0)