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

Commit 0f4fdb9

Browse files
authored
FEATURE: Force sidebar for bot conversations (#1266)
1 parent 05f997e commit 0f4fdb9

File tree

6 files changed

+165
-113
lines changed

6 files changed

+165
-113
lines changed

assets/javascripts/discourse/components/ai-bot-sidebar-new-conversation.gjs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
import Component from "@glimmer/component";
22
import { service } from "@ember/service";
33
import DButton from "discourse/components/d-button";
4+
import { AI_CONVERSATIONS_PANEL } from "../services/ai-conversations-sidebar-manager";
45

56
export default class AiBotSidebarNewConversation extends Component {
6-
@service router;
7+
@service sidebarState;
78

8-
get show() {
9-
// don't show the new question button on the conversations home page
10-
return this.router.currentRouteName !== "discourse-ai-bot-conversations";
9+
get shouldRender() {
10+
return this.sidebarState.isCurrentPanel(AI_CONVERSATIONS_PANEL);
1111
}
1212

1313
<template>
14-
{{#if this.show}}
14+
{{#if this.shouldRender}}
1515
<DButton
1616
@route="/discourse-ai/ai-bot/conversations"
1717
@label="discourse_ai.ai_bot.conversations.new"
Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
import { service } from "@ember/service";
12
import DiscourseRoute from "discourse/routes/discourse";
23

3-
export default class DiscourseAiBotConversationsRoute extends DiscourseRoute {}
4+
export default class DiscourseAiBotConversationsRoute extends DiscourseRoute {
5+
@service aiConversationsSidebarManager;
6+
7+
activate() {
8+
super.activate(...arguments);
9+
this.aiConversationsSidebarManager.forceCustomSidebar();
10+
}
11+
12+
deactivate() {
13+
super.deactivate(...arguments);
14+
this.aiConversationsSidebarManager.stopForcingCustomSidebar();
15+
}
16+
}

assets/javascripts/discourse/services/ai-bot-conversations-hidden-submit.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export default class AiBotConversationsHiddenSubmit extends Service {
4040
const personaWithUsername = this.currentUser.ai_enabled_personas.find(
4141
(persona) => persona.username
4242
);
43+
4344
// this is a total hack, the composer is hidden on the homepage with CSS
4445
await this.composer.open({
4546
action: Composer.PRIVATE_MESSAGE,
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { alias } from "@ember/object/computed";
2+
import Service, { service } from "@ember/service";
3+
import { MAIN_PANEL } from "discourse/lib/sidebar/panels";
4+
5+
export const AI_CONVERSATIONS_PANEL = "ai-conversations";
6+
7+
export default class AiConversationsSidebarManager extends Service {
8+
@service sidebarState;
9+
10+
@alias("sidebarState.isForcingSidebar") isForcingSidebar;
11+
12+
forceCustomSidebar() {
13+
// Set the panel to your custom panel
14+
this.sidebarState.setPanel(AI_CONVERSATIONS_PANEL);
15+
16+
// Use separated mode to ensure independence from hamburger menu
17+
this.sidebarState.setSeparatedMode();
18+
19+
// Hide panel switching buttons to keep UI clean
20+
this.sidebarState.hideSwitchPanelButtons();
21+
22+
this.isForcingSidebar = true;
23+
document.body.classList.add("has-ai-conversations-sidebar");
24+
return true;
25+
}
26+
27+
stopForcingCustomSidebar() {
28+
// This method is called when leaving your route
29+
// Only restore main panel if we previously forced ours
30+
document.body.classList.remove("has-ai-conversations-sidebar");
31+
if (this.isForcingSidebar) {
32+
this.sidebarState.setPanel(MAIN_PANEL); // Return to main sidebar panel
33+
this.isForcingSidebar = false;
34+
}
35+
}
36+
}

assets/javascripts/initializers/ai-bot-sidebar.js renamed to assets/javascripts/initializers/ai-conversations-sidebar.js

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,16 @@ import { ajax } from "discourse/lib/ajax";
33
import { withPluginApi } from "discourse/lib/plugin-api";
44
import { i18n } from "discourse-i18n";
55
import AiBotSidebarNewConversation from "../discourse/components/ai-bot-sidebar-new-conversation";
6+
import { AI_CONVERSATIONS_PANEL } from "../discourse/services/ai-conversations-sidebar-manager";
67

78
export default {
8-
name: "custom-sidebar-bot-messages",
9+
name: "ai-conversations-sidebar",
10+
911
initialize() {
10-
withPluginApi("1.37.1", (api) => {
12+
withPluginApi("1.8.0", (api) => {
13+
const aiConversationsSidebarManager = api.container.lookup(
14+
"service:ai-conversations-sidebar-manager"
15+
);
1116
const currentUser = api.container.lookup("service:current-user");
1217
const appEvents = api.container.lookup("service:app-events");
1318
const messageBus = api.container.lookup("service:message-bus");
@@ -18,9 +23,24 @@ export default {
1823

1924
// TODO: Replace
2025
const recentConversations = 10;
26+
// Step 1: Add a custom sidebar panel
27+
api.addSidebarPanel(
28+
(BaseCustomSidebarPanel) =>
29+
class AiConversationsSidebarPanel extends BaseCustomSidebarPanel {
30+
key = AI_CONVERSATIONS_PANEL;
31+
hidden = true; // Hide from panel switching UI
32+
displayHeader = true;
33+
expandActiveSection = true;
34+
35+
// Optional - customize if needed
36+
// switchButtonLabel = "Your Panel";
37+
// switchButtonIcon = "cog";
38+
}
39+
);
2140

22-
api.renderInOutlet("after-sidebar-sections", AiBotSidebarNewConversation);
41+
api.renderInOutlet("sidebar-footer-actions", AiBotSidebarNewConversation);
2342

43+
// Step 2: Add a custom section to your panel
2444
api.addSidebarSection(
2545
(BaseCustomSidebarSection, BaseCustomSidebarSectionLink) => {
2646
return class extends BaseCustomSidebarSection {
@@ -56,7 +76,9 @@ export default {
5676
this.isFetching = false;
5777
this.buildSidebarLinks();
5878
})
59-
.catch(() => (this.isFetching = false));
79+
.catch((e) => {
80+
this.isFetching = false;
81+
});
6082
}
6183

6284
addNewMessage(newTopic) {
@@ -130,7 +152,31 @@ export default {
130152
return this.links?.length > 0;
131153
}
132154
};
133-
}
155+
},
156+
AI_CONVERSATIONS_PANEL
157+
);
158+
159+
api.modifyClass(
160+
"route:topic",
161+
(Superclass) =>
162+
class extends Superclass {
163+
activate() {
164+
super.activate();
165+
const topic = this.modelFor("topic");
166+
if (
167+
topic &&
168+
topic.archetype === "private_message" &&
169+
topic.ai_persona_name
170+
) {
171+
aiConversationsSidebarManager.forceCustomSidebar();
172+
}
173+
}
174+
175+
deactivate() {
176+
super.activate();
177+
aiConversationsSidebarManager.stopForcingCustomSidebar();
178+
}
179+
}
134180
);
135181
});
136182
},

0 commit comments

Comments
 (0)