diff --git a/clefincode_chat/__init__.py b/clefincode_chat/__init__.py
index 9456cbf..1da7fb6 100644
--- a/clefincode_chat/__init__.py
+++ b/clefincode_chat/__init__.py
@@ -1 +1 @@
-__version__ = '1.3.912'
\ No newline at end of file
+__version__ = '1.3.913'
\ No newline at end of file
diff --git a/clefincode_chat/desk/custom_load.py b/clefincode_chat/desk/custom_load.py
index bac9a94..b697711 100644
--- a/clefincode_chat/desk/custom_load.py
+++ b/clefincode_chat/desk/custom_load.py
@@ -192,67 +192,96 @@ def add_chat_topics(doc, docinfo):
docinfo.chat_topics = []
chat_topics = frappe.db.sql(
- f"""
- SELECT
- ref.parent AS topic_name,
- topic.chat_channel,
- topic.is_private,
- topic.subject,
- topic.owner,
- topic.creation AS topic_creation,
- topic.topic_status,
-
- {bucket_expr} AS period_bucket,
-
- COALESCE(MIN(msg.send_date), topic.creation) AS period_start,
- CASE
- WHEN MIN(msg.send_date) IS NOT NULL
- AND MAX(msg.send_date) IS NOT NULL
- AND MIN(msg.send_date) = MAX(msg.send_date)
- THEN DATE_ADD(MAX(msg.send_date), INTERVAL 1 SECOND)
- ELSE COALESCE(MAX(msg.send_date), topic.creation)
- END AS period_end,
-
- MIN(msg.send_date) AS first_message_date,
- MAX(msg.send_date) AS last_message_date,
- SUBSTRING_INDEX(
- GROUP_CONCAT(msg.name ORDER BY msg.send_date ASC),
- ',',
- 1
- ) AS first_message_name,
- COUNT(msg.name) AS message_count
-
- FROM `tabClefinCode Chat Topic Reference` AS ref
-
- JOIN `tabClefinCode Chat Topic` AS topic
- ON ref.parent = topic.name
-
- LEFT JOIN `tabClefinCode Chat Message` AS msg
- ON msg.chat_topic = topic.name
- AND msg.chat_channel = topic.chat_channel
- AND IFNULL(msg.is_deleted, 0) = 0
-
- WHERE
- ref.docname = %s
- AND ref.active = 1
-
- GROUP BY
- ref.parent,
- topic.chat_channel,
- topic.is_private,
- topic.subject,
- topic.owner,
- topic.creation,
- topic.topic_status,
- {bucket_expr}
-
- ORDER BY
- COALESCE(MIN(msg.send_date), topic.creation) DESC
- """,
- (doc.name,),
- as_dict=True
- )
-
+ f"""
+ SELECT
+ ref.parent AS topic_name,
+ topic.chat_channel,
+ topic.is_private,
+ topic.subject,
+ topic.owner,
+ topic.creation AS topic_creation,
+ topic.topic_status,
+
+ {bucket_expr} AS period_bucket,
+
+ COALESCE(MIN(msg.send_date), topic.creation) AS period_start,
+
+ CASE
+ WHEN MAX(msg.send_date) IS NOT NULL
+ THEN DATE_ADD(
+ MAX(msg.send_date),
+ INTERVAL 1 SECOND
+ )
+ ELSE topic.creation
+ END AS period_end,
+
+ MIN(msg.send_date) AS first_message_date,
+ MAX(msg.send_date) AS last_message_date,
+
+ SUBSTRING_INDEX(
+ GROUP_CONCAT(
+ msg.name
+ ORDER BY msg.send_date ASC, msg.creation ASC
+ ),
+ ',',
+ 1
+ ) AS first_message_name,
+
+ COUNT(msg.name) AS message_count
+
+ FROM `tabClefinCode Chat Topic Reference` AS ref
+
+ JOIN `tabClefinCode Chat Topic` AS topic
+ ON ref.parent = topic.name
+
+ LEFT JOIN `tabClefinCode Chat Message` AS msg
+ ON msg.chat_topic = topic.name
+ AND msg.chat_channel = topic.chat_channel
+ AND IFNULL(msg.is_deleted, 0) = 0
+
+ AND LOWER(
+ TRIM(IFNULL(msg.message_type, ''))
+ ) != 'information'
+
+ AND LOWER(
+ REPLACE(
+ REPLACE(
+ TRIM(IFNULL(msg.message_template_type, '')),
+ '-',
+ ' '
+ ),
+ '_',
+ ' '
+ )
+ ) NOT IN (
+ 'set topic',
+ 'remove topic',
+ 'close topic',
+ 'reopen topic'
+ )
+
+ WHERE
+ ref.docname = %s
+ AND ref.active = 1
+
+ GROUP BY
+ ref.parent,
+ topic.chat_channel,
+ topic.is_private,
+ topic.subject,
+ topic.owner,
+ topic.creation,
+ topic.topic_status,
+ {bucket_expr}
+
+ HAVING COUNT(msg.name) > 0
+
+ ORDER BY
+ MIN(msg.send_date) DESC
+ """,
+ (doc.name,),
+ as_dict=True
+ )
for chat_topic_data in chat_topics:
chat_channel = chat_topic_data.chat_channel
is_private = chat_topic_data.is_private
diff --git a/clefincode_chat/public/js/components/erpnext_chat_space.js b/clefincode_chat/public/js/components/erpnext_chat_space.js
index b9a753a..1f7b497 100644
--- a/clefincode_chat/public/js/components/erpnext_chat_space.js
+++ b/clefincode_chat/public/js/components/erpnext_chat_space.js
@@ -38,10 +38,122 @@ import ChatContactList from "./erpnext_chat_contact_list";
import { add_group_member, create_group } from "./erpnext_chat_contact_list";
+function buildTopicWindowKey({
+ source = "base",
+ chatChannel = "",
+ chatTopic = "",
+ fromDate = "",
+ toDate = "",
+ firstMessageName = "",
+} = {}) {
+ const parts = [
+ "topic-window",
+ source,
+ chatChannel,
+ chatTopic,
+ ];
+
+ if (source === "timeline") {
+ parts.push(
+ fromDate || "",
+ toDate || "",
+ firstMessageName || ""
+ );
+ }
+
+ return parts
+ .map((value) =>
+ encodeURIComponent(String(value || "").trim())
+ )
+ .join("::");
+}
+
+function findTopicWindowInstance(windowKey) {
+ if (!windowKey) {
+ return null;
+ }
+
+ const instances = window.CCChatSpaceInstances || [];
+
+ return (
+ instances.find((instance) => {
+ if (!instance) {
+ return false;
+ }
+
+ const instanceKey =
+ instance.topic_window_key ||
+ instance.profile?.topic_window_key ||
+ instance.$wrapper?.attr?.(
+ "data-topic-window-key"
+ ) ||
+ "";
+
+ return String(instanceKey) === String(windowKey);
+ }) || null
+ );
+}
+
+function showTopicWindowInstance(instance) {
+ if (!instance?.$wrapper?.length) {
+ return;
+ }
+
+ const $window = instance.$wrapper.closest(".chat-window");
+
+ if (!$window.length) {
+ return;
+ }
+
+ const $expandButton = $window.find(
+ ".expand-chat-window"
+ );
+
+ if ($expandButton.length) {
+ $expandButton.trigger("click");
+ }
+
+ $window.show();
+}
+
export default class ChatSpace {
constructor(opts) {
this.$wrapper = opts.$wrapper;
this.profile = opts.profile;
+
+ this.topic_window_key =
+ opts.topic_window_key ||
+ this.profile?.topic_window_key ||
+ null;
+
+ this.topic_window_source =
+ opts.topic_window_source ||
+ this.profile?.topic_window_source ||
+ "base";
+
+ if (this.topic_window_key) {
+ this.profile.topic_window_key =
+ this.topic_window_key;
+ }
+
+ this.profile.topic_window_source =
+ this.topic_window_source;
+
+ if (
+ this.topic_window_key &&
+ this.$wrapper?.length
+ ) {
+ this.$wrapper
+ .attr(
+ "data-topic-window-key",
+ this.topic_window_key
+ )
+ .attr(
+ "data-topic-source",
+ this.topic_window_source
+ );
+ }
+
this.$chat_room = opts.$chat_room;
this.new_group = opts.new_group;
this.chat_list = opts.chat_list;
@@ -356,16 +468,47 @@ isRealTopicTimelineMessage(message = {}) {
return true;
}
-makeTopicStartSeparatorHtml(topicName, topicSubject = null, topicColor = null) {
+makeTopicStartSeparatorHtml(
+ topicName,
+ topicSubject = null,
+ topicColor = null
+) {
if (!topicName) return "";
- if (this.isDedicatedTopicContext?.()) return "";
- const color = topicColor || this.getTopicColor(topicName);
- const safeTopicName = frappe.utils.escape_html(String(topicName));
+
+ if (this.shouldHideTopicSeparators()) {
+ return "";
+ }
+
+ const color =
+ topicColor ||
+ this.getTopicColor(topicName);
+
+ const safeTopicName =
+ frappe.utils.escape_html(String(topicName));
+
const displaySubject = this.formatTopicSeparatorSubject
- ? this.formatTopicSeparatorSubject(topicSubject, topicName)
- : String(topicSubject || topicName || __("Topic")).replace(/^topic\s*:\s*/i, "").trim();
- const safeSubject = frappe.utils.escape_html(displaySubject || topicName || __("Topic"));
- const safeColor = frappe.utils.escape_html(color || "");
+ ? this.formatTopicSeparatorSubject(
+ topicSubject,
+ topicName
+ )
+ : String(
+ topicSubject ||
+ topicName ||
+ __("Topic")
+ )
+ .replace(/^topic\s*:\s*/i, "")
+ .trim();
+
+ const safeSubject =
+ frappe.utils.escape_html(
+ displaySubject ||
+ topicName ||
+ __("Topic")
+ );
+
+ const safeColor =
+ frappe.utils.escape_html(color || "");
+
return `
- ${safeSubject}
+
+ ${safeSubject}
+