DEV: Group PMs by date (#1287)
# Preview https://github.com/user-attachments/assets/3fe3ac8f-c938-4df4-9afe-11980046944d # Details - Group pms by `last_posted_at`. In this first iteration we are group by `7 days`, `30 days`, then by month beyond that. - I inject a sidebar section link with the relative (last_posted_at) date and then update a tracked value to ensure we don't do it again. Then for each month beyond the first 30days, I add a value to the `loadedMonthLabels` set and we reference that (plus the year) to see if we need to load a new month label. - I took the creative liberty to remove the `Conversations` section label - this had no purpose - I hid the _collapse all sidebar sections_ carrot. This had no purpose. - Swap `BasicTopicSerializer` to `ListableTopicSerializer` to get access to `last_posted_at`
This commit is contained in:
parent
60ea590ba5
commit
cd0cfc0bfc
|
@ -10,7 +10,6 @@ module DiscourseAi
|
|||
page = params[:page].to_i
|
||||
per_page = params[:per_page]&.to_i || 40
|
||||
|
||||
bot_user_ids = EntryPoint.all_bot_ids
|
||||
base_query =
|
||||
Topic
|
||||
.private_messages_for_user(current_user)
|
||||
|
@ -26,7 +25,7 @@ module DiscourseAi
|
|||
pms = base_query.order(last_posted_at: :desc).offset(page * per_page).limit(per_page)
|
||||
|
||||
render json: {
|
||||
conversations: serialize_data(pms, BasicTopicSerializer),
|
||||
conversations: serialize_data(pms, ListableTopicSerializer),
|
||||
meta: {
|
||||
total: total,
|
||||
page: page,
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import { tracked } from "@glimmer/tracking";
|
||||
import { htmlSafe } from "@ember/template";
|
||||
import { TrackedArray } from "@ember-compat/tracked-built-ins";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
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 AiBotSidebarNewConversation from "../discourse/components/ai-bot-sidebar-new-conversation";
|
||||
|
@ -85,6 +87,9 @@ export default {
|
|||
@tracked links = new TrackedArray();
|
||||
@tracked topics = [];
|
||||
@tracked hasMore = [];
|
||||
@tracked loadedSevenDayLabel = false;
|
||||
@tracked loadedThirtyDayLabel = false;
|
||||
@tracked loadedMonthLabels = new Set();
|
||||
page = 0;
|
||||
isFetching = false;
|
||||
totalTopicsCount = 0;
|
||||
|
@ -127,7 +132,14 @@ export default {
|
|||
}
|
||||
|
||||
addNewPMToSidebar(topic) {
|
||||
this.links = [new AiConversationLink(topic), ...this.links];
|
||||
// Reset category labels since we're adding a new topic
|
||||
this.loadedSevenDayLabel = false;
|
||||
this.loadedThirtyDayLabel = false;
|
||||
this.loadedMonthLabels.clear();
|
||||
|
||||
this.topics = [topic, ...this.topics];
|
||||
this.buildSidebarLinks();
|
||||
|
||||
this.watchForTitleUpdate(topic);
|
||||
}
|
||||
|
||||
|
@ -206,10 +218,71 @@ export default {
|
|||
this.fetchMessages(true);
|
||||
}
|
||||
|
||||
buildSidebarLinks() {
|
||||
this.links = this.topics.map(
|
||||
(topic) => new AiConversationLink(topic)
|
||||
groupByDate(topic) {
|
||||
const now = new Date();
|
||||
const lastPostedAt = new Date(topic.last_posted_at);
|
||||
const daysDiff = Math.round(
|
||||
(now - lastPostedAt) / (1000 * 60 * 60 * 24)
|
||||
);
|
||||
|
||||
// Last 7 days group
|
||||
if (daysDiff <= 7) {
|
||||
if (!this.loadedSevenDayLabel) {
|
||||
this.loadedSevenDayLabel = true;
|
||||
return {
|
||||
text: i18n("discourse_ai.ai_bot.conversations.last_7_days"),
|
||||
classNames: "date-heading",
|
||||
name: "date-heading-last-7-days",
|
||||
};
|
||||
}
|
||||
}
|
||||
// Last 30 days group
|
||||
else if (daysDiff <= 30) {
|
||||
if (!this.loadedThirtyDayLabel) {
|
||||
this.loadedThirtyDayLabel = true;
|
||||
return {
|
||||
text: i18n(
|
||||
"discourse_ai.ai_bot.conversations.last_30_days"
|
||||
),
|
||||
classNames: "date-heading",
|
||||
name: "date-heading-last-30-days",
|
||||
};
|
||||
}
|
||||
}
|
||||
// Group by month for older conversations
|
||||
else {
|
||||
const month = lastPostedAt.getMonth();
|
||||
const year = lastPostedAt.getFullYear();
|
||||
const monthKey = `${year}-${month}`;
|
||||
|
||||
if (!this.loadedMonthLabels.has(monthKey)) {
|
||||
this.loadedMonthLabels.add(monthKey);
|
||||
|
||||
const formattedDate = autoUpdatingRelativeAge(
|
||||
new Date(topic.last_posted_at)
|
||||
);
|
||||
|
||||
return {
|
||||
text: htmlSafe(formattedDate),
|
||||
classNames: "date-heading",
|
||||
name: `date-heading-${monthKey}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buildSidebarLinks() {
|
||||
// Reset date header tracking
|
||||
this.loadedSevenDayLabel = false;
|
||||
this.loadedThirtyDayLabel = false;
|
||||
this.loadedMonthLabels.clear();
|
||||
|
||||
this.links = [...this.topics].flatMap((topic) => {
|
||||
const dateLabel = this.groupByDate(topic);
|
||||
return dateLabel
|
||||
? [dateLabel, new AiConversationLink(topic)]
|
||||
: [new AiConversationLink(topic)];
|
||||
});
|
||||
}
|
||||
|
||||
watchForTitleUpdate(topic) {
|
||||
|
|
|
@ -10,6 +10,10 @@ body.has-ai-conversations-sidebar {
|
|||
margin: 1.8em 1rem 0;
|
||||
}
|
||||
|
||||
.sidebar-toggle-all-sections {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sidebar-wrapper {
|
||||
.ai-conversations-panel {
|
||||
padding-top: 1em;
|
||||
|
@ -18,19 +22,23 @@ body.has-ai-conversations-sidebar {
|
|||
// ai related sidebar content
|
||||
[data-section-name="ai-conversations-history"] {
|
||||
.sidebar-section-header-wrapper {
|
||||
pointer-events: none;
|
||||
font-size: var(--font-down-1);
|
||||
|
||||
.sidebar-section-header-caret {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sidebar-section-header-text {
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sidebar-section-link-wrapper {
|
||||
.sidebar-section-link.date-heading {
|
||||
pointer-events: none;
|
||||
cursor: default;
|
||||
color: var(--primary-medium);
|
||||
opacity: 0.8;
|
||||
font-weight: 700;
|
||||
margin-top: 1em;
|
||||
|
||||
&[data-link-name="date-heading-last-7-days"] {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-section-link {
|
||||
height: unset;
|
||||
padding-block: 0.65em;
|
||||
|
|
|
@ -727,6 +727,8 @@ en:
|
|||
new: "New Question"
|
||||
min_input_length_message: "Message must be longer than 10 characters"
|
||||
messages_sidebar_title: "Conversations"
|
||||
last_7_days: "Last 7 days"
|
||||
last_30_days: "Last 30 days"
|
||||
sentiments:
|
||||
dashboard:
|
||||
title: "Sentiment"
|
||||
|
|
|
@ -49,6 +49,7 @@ RSpec.describe "AI Bot - Homepage", type: :system do
|
|||
:private_message_topic,
|
||||
title: "This is my special PM",
|
||||
user: user,
|
||||
last_posted_at: Time.zone.now,
|
||||
topic_allowed_users: [
|
||||
Fabricate.build(:topic_allowed_user, user: user),
|
||||
Fabricate.build(:topic_allowed_user, user: bot_user),
|
||||
|
@ -150,18 +151,35 @@ RSpec.describe "AI Bot - Homepage", type: :system do
|
|||
|
||||
expect(ai_pm_homepage).to have_homepage
|
||||
expect(sidebar).to have_section("ai-conversations-history")
|
||||
expect(sidebar).to have_section_link("Last 7 days")
|
||||
expect(sidebar).to have_section_link(pm.title)
|
||||
expect(sidebar).to have_no_css("button.ai-new-question-button")
|
||||
end
|
||||
|
||||
it "displays last_30_days label in the sidebar" do
|
||||
pm.update!(last_posted_at: Time.zone.now - 28.days)
|
||||
visit "/"
|
||||
header.click_bot_button
|
||||
|
||||
expect(ai_pm_homepage).to have_homepage
|
||||
expect(sidebar).to have_section_link("Last 30 days")
|
||||
end
|
||||
|
||||
it "displays month and year label in the sidebar for older conversations" do
|
||||
pm.update!(last_posted_at: "2024-04-10 15:39:11.406192000 +00:00")
|
||||
visit "/"
|
||||
header.click_bot_button
|
||||
|
||||
expect(ai_pm_homepage).to have_homepage
|
||||
expect(sidebar).to have_section_link("Apr 2024")
|
||||
end
|
||||
|
||||
it "navigates to the bot conversation when clicked" do
|
||||
visit "/"
|
||||
header.click_bot_button
|
||||
|
||||
expect(ai_pm_homepage).to have_homepage
|
||||
sidebar.find(
|
||||
".sidebar-section[data-section-name='ai-conversations-history'] a.sidebar-section-link",
|
||||
).click
|
||||
ai_pm_homepage.click_fist_sidebar_conversation
|
||||
expect(topic_page).to have_topic_title(pm.title)
|
||||
end
|
||||
|
||||
|
@ -173,9 +191,7 @@ RSpec.describe "AI Bot - Homepage", type: :system do
|
|||
expect(header).to have_icon_in_bot_button(icon: "shuffle")
|
||||
|
||||
# Go to a PM and assert that the icon is still shuffle
|
||||
sidebar.find(
|
||||
".sidebar-section[data-section-name='ai-conversations-history'] a.sidebar-section-link",
|
||||
).click
|
||||
ai_pm_homepage.click_fist_sidebar_conversation
|
||||
expect(header).to have_icon_in_bot_button(icon: "shuffle")
|
||||
|
||||
# Go back home and assert that the icon is now robot again
|
||||
|
|
|
@ -40,6 +40,12 @@ module PageObjects
|
|||
page.find(".ai-new-question-button").click
|
||||
end
|
||||
|
||||
def click_fist_sidebar_conversation
|
||||
page.find(
|
||||
".sidebar-section[data-section-name='ai-conversations-history'] a.sidebar-section-link:not(.date-heading)",
|
||||
).click
|
||||
end
|
||||
|
||||
def persona_selector
|
||||
PageObjects::Components::SelectKit.new(".persona-llm-selector__persona-dropdown")
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue