diff --git a/frontend/src/components/feature/GlobalSearch/MessageBox.tsx b/frontend/src/components/feature/GlobalSearch/MessageBox.tsx
index 997c67582..d26e56c12 100644
--- a/frontend/src/components/feature/GlobalSearch/MessageBox.tsx
+++ b/frontend/src/components/feature/GlobalSearch/MessageBox.tsx
@@ -10,7 +10,7 @@ import { DateMonthYear } from "@/utils/dateConversions"
type MessageBoxProps = {
message: Message & { workspace?: string }
- handleScrollToMessage: (messageName: string, channelID: string, workspace?: string) => void
+ handleScrollToMessage?: (messageName: string, channelID: string, workspace?: string) => void
}
export const MessageBox = ({ message, handleScrollToMessage }: MessageBoxProps) => {
@@ -44,15 +44,15 @@ export const MessageBox = ({ message, handleScrollToMessage }: MessageBoxProps)
- handleScrollToMessage(message.name, channel_id, message.workspace)}>
+ {handleScrollToMessage ? handleScrollToMessage(message.name, channel_id, message.workspace)}>
View in channel
-
+ : null}
-
-
+
+
diff --git a/frontend/src/components/feature/channel-details/rename-channel/EditChannelNameButton.tsx b/frontend/src/components/feature/channel-details/rename-channel/EditChannelNameButton.tsx
index eb63a9b22..67fb3ae7e 100644
--- a/frontend/src/components/feature/channel-details/rename-channel/EditChannelNameButton.tsx
+++ b/frontend/src/components/feature/channel-details/rename-channel/EditChannelNameButton.tsx
@@ -7,14 +7,16 @@ import { useState } from "react"
import { DIALOG_CONTENT_CLASS } from '@/utils/layout/dialog'
import { useIsDesktop } from '@/hooks/useMediaQuery'
import { DrawerContent, DrawerTrigger, Drawer } from '@/components/layout/Drawer'
+import clsx from 'clsx'
interface EditChannelNameButtonProps extends IconButtonProps {
channelID: string,
channel_name: string,
- channelType: ChannelListItem['type']
+ channelType: ChannelListItem['type'],
+ buttonVisible?: boolean,
}
-export const EditChannelNameButton = ({ channelID, channel_name, channelType, ...props }: EditChannelNameButtonProps) => {
+export const EditChannelNameButton = ({ channelID, channel_name, channelType, buttonVisible = false, ...props }: EditChannelNameButtonProps) => {
const [open, setOpen] = useState(false);
@@ -31,7 +33,7 @@ export const EditChannelNameButton = ({ channelID, channel_name, channelType, ..
@@ -53,7 +55,7 @@ export const EditChannelNameButton = ({ channelID, channel_name, channelType, ..
diff --git a/frontend/src/components/feature/chat-header/ChannelHeader.tsx b/frontend/src/components/feature/chat-header/ChannelHeader.tsx
index 39944c5c9..e823947b8 100644
--- a/frontend/src/components/feature/chat-header/ChannelHeader.tsx
+++ b/frontend/src/components/feature/chat-header/ChannelHeader.tsx
@@ -7,6 +7,7 @@ import ChannelHeaderMenu from "./ChannelHeaderMenu"
import { ViewChannelMemberAvatars } from "./ViewChannelMemberAvatars"
import { BiChevronLeft } from "react-icons/bi"
import { Link } from "react-router-dom"
+import { ViewPinnedMessagesButton } from "../pinned-messages/ViewPinnedMessagesButton"
interface ChannelHeaderProps {
channelData: ChannelListItem
@@ -34,7 +35,8 @@ export const ChannelHeader = ({ channelData }: ChannelHeaderProps) => {
}}
className="mb-0.5 text-ellipsis line-clamp-1">{channelData.channel_name}
-
+
+
diff --git a/frontend/src/components/feature/chat/ChatMessage/LeftRightLayout/LeftRightLayout.tsx b/frontend/src/components/feature/chat/ChatMessage/LeftRightLayout/LeftRightLayout.tsx
index 53ff3f236..7be0811a1 100644
--- a/frontend/src/components/feature/chat/ChatMessage/LeftRightLayout/LeftRightLayout.tsx
+++ b/frontend/src/components/feature/chat/ChatMessage/LeftRightLayout/LeftRightLayout.tsx
@@ -4,7 +4,7 @@ import { MessageContent, MessageSenderAvatar, UserHoverCard } from "../MessageIt
import { Box, BoxProps, ContextMenu, Flex, Text } from "@radix-ui/themes"
import { MessageReactions } from "../MessageReactions"
import { DateTooltip, DateTooltipShort } from "../Renderers/DateTooltip"
-import { RiShareForwardFill } from "react-icons/ri"
+import { RiPushpinFill, RiShareForwardFill } from "react-icons/ri"
import { ReplyMessageBox } from "../ReplyMessageBox/ReplyMessageBox"
import { useContext, useMemo, useState } from "react"
import clsx from "clsx"
@@ -106,7 +106,7 @@ export const LeftRightLayout = ({ message, user, isActive, isHighlighted, onRepl
: null}
{message.is_forwarded === 1 && forwarded}
-
+ {message.is_pinned === 1 && Pinned}
{linked_message && replied_message_details &&
}
+
@@ -165,4 +167,32 @@ const SaveMessageAction = ({ message }: { message: Message }) => {
+}
+
+
+const PinMessageAction = ({ message }: { message: Message }) => {
+
+ const isPinned = message.is_pinned
+ const { call } = useContext(FrappeContext) as FrappeConfig
+
+ const handlePin = () => {
+ call.post('raven.api.raven_channel.toggle_pin_message', {
+ channel_id: message.channel_id,
+ message_id: message.name,
+ }).then(() => {
+ toast.success(`Message ${isPinned ? 'unpinned' : 'pinned'}`)
+ }).catch((e) => {
+ toast.error('Could not perform the action', {
+ description: getErrorMessage(e)
+ })
+ })
+ }
+
+ return
+
+ {!isPinned ? : }
+ {!isPinned ? "Pin" : "Unpin"}
+
+
+
}
\ No newline at end of file
diff --git a/frontend/src/components/feature/chat/ChatMessage/MessageItem.tsx b/frontend/src/components/feature/chat/ChatMessage/MessageItem.tsx
index d4b8fc908..f49ff88f7 100644
--- a/frontend/src/components/feature/chat/ChatMessage/MessageItem.tsx
+++ b/frontend/src/components/feature/chat/ChatMessage/MessageItem.tsx
@@ -19,7 +19,7 @@ import { ReplyMessageBox } from './ReplyMessageBox/ReplyMessageBox'
import { generateAvatarColor } from '../../selectDropdowns/GenerateAvatarColor'
import { DoctypeLinkRenderer } from './Renderers/DoctypeLinkRenderer'
import { useDebounce } from '@/hooks/useDebounce'
-import { RiRobot2Fill, RiShareForwardFill } from 'react-icons/ri'
+import { RiPushpinFill, RiRobot2Fill, RiShareForwardFill } from 'react-icons/ri'
import { useIsDesktop } from '@/hooks/useMediaQuery'
import { useDoubleTap } from 'use-double-tap'
import useOutsideClick from '@/hooks/useOutsideClick'
@@ -179,6 +179,7 @@ export const MessageItem = ({ message, setDeleteMessage, isHighlighted, onReplyM
: null}
{/* Message content goes here */}
{message.is_forwarded === 1 && forwarded}
+ {message.is_pinned === 1 && Pinned}
{/* If it's a reply, then show the linked message */}
{linked_message && replied_message_details && {
maxFileSize={10000000}>
{canUserSendMessage &&
diff --git a/frontend/src/components/feature/chat/ChatStream/ChatStream.tsx b/frontend/src/components/feature/chat/ChatStream/ChatStream.tsx
index 19e2bf082..be0661154 100644
--- a/frontend/src/components/feature/chat/ChatStream/ChatStream.tsx
+++ b/frontend/src/components/feature/chat/ChatStream/ChatStream.tsx
@@ -66,15 +66,16 @@ import SystemMessageBlock from '../ChatMessage/SystemMessageBlock'
type Props = {
channelID: string,
replyToMessage: (message: Message) => void,
- showThreadButton?: boolean
+ showThreadButton?: boolean,
+ pinnedMessagesString?: string
}
-const ChatStream = ({ channelID, replyToMessage, showThreadButton = true }: Props) => {
+const ChatStream = ({ channelID, replyToMessage, showThreadButton = true, pinnedMessagesString }: Props) => {
const scrollRef = useRef(null)
- const { messages, hasOlderMessages, loadOlderMessages, goToLatestMessages, hasNewMessages, error, loadNewerMessages, isLoading, highlightedMessage, scrollToMessage } = useChatStream(channelID, scrollRef)
+ const { messages, hasOlderMessages, loadOlderMessages, goToLatestMessages, hasNewMessages, error, loadNewerMessages, isLoading, highlightedMessage, scrollToMessage } = useChatStream(channelID, scrollRef, pinnedMessagesString)
const { setDeleteMessage, ...deleteProps } = useDeleteMessage()
const { setEditMessage, ...editProps } = useEditMessage()
diff --git a/frontend/src/components/feature/chat/ChatStream/useChatStream.ts b/frontend/src/components/feature/chat/ChatStream/useChatStream.ts
index b6dd1c231..2222ab5b9 100644
--- a/frontend/src/components/feature/chat/ChatStream/useChatStream.ts
+++ b/frontend/src/components/feature/chat/ChatStream/useChatStream.ts
@@ -24,7 +24,7 @@ type MessageDateBlock = Message | {
/**
* Hook to fetch messages to be rendered on the chat interface
*/
-const useChatStream = (channelID: string, scrollRef: MutableRefObject) => {
+const useChatStream = (channelID: string, scrollRef: MutableRefObject, pinnedMessagesString?: string) => {
const location = useLocation()
const navigate = useNavigate()
@@ -427,6 +427,9 @@ const useChatStream = (channelID: string, scrollRef: MutableRefObject messageID.trim())
+
const messages = [...data.message.messages]
// Messages are already sorted by date - from latest to oldest
@@ -445,7 +448,11 @@ const useChatStream = (channelID: string, scrollRef: MutableRefObject= 0; i--) {
@@ -469,15 +476,17 @@ const useChatStream = (channelID: string, scrollRef: MutableRefObject 120000) {
messagesWithDateSeparators.push({
...message,
- is_continuation: 0
+ is_continuation: 0,
+ is_pinned: pinnedMessageIDs.includes(message.name) ? 1 : 0
})
} else {
- messagesWithDateSeparators.push({ ...message, is_continuation: 1 })
+ messagesWithDateSeparators.push({ ...message, is_continuation: 1, is_pinned: pinnedMessageIDs.includes(message.name) ? 1 : 0 })
}
currentDate = messageDate
currentDateTime = new Date(message.creation).getTime()
@@ -489,7 +498,7 @@ const useChatStream = (channelID: string, scrollRef: MutableRefObject {
// Check if the message is in the messages array
diff --git a/frontend/src/components/feature/pinned-messages/PinnedMessageModalContent.tsx b/frontend/src/components/feature/pinned-messages/PinnedMessageModalContent.tsx
new file mode 100644
index 000000000..df3d9afd7
--- /dev/null
+++ b/frontend/src/components/feature/pinned-messages/PinnedMessageModalContent.tsx
@@ -0,0 +1,37 @@
+import { Dialog, Flex, IconButton, Text } from '@radix-ui/themes'
+import { useFrappeGetCall } from 'frappe-react-sdk'
+import { useParams } from 'react-router-dom'
+import { Message } from '../../../../../types/Messaging/Message'
+import { ErrorBanner } from '@/components/layout/AlertBanner/ErrorBanner'
+import { MessageBox } from '../GlobalSearch/MessageBox'
+import { IoClose } from 'react-icons/io5'
+
+export const PinnedMessageModalContent = ({ onClose }: { onClose: () => void }) => {
+
+ const { channelID } = useParams<{ channelID: string }>()
+
+ const { data, error } = useFrappeGetCall<{ message: Message[] }>("raven.api.raven_message.get_pinned_messages", { 'channel_id': channelID }, undefined, {
+ revalidateOnFocus: false
+ })
+
+ return (
+ <>
+
+
+ Pinned Messages
+
+
+
+
+
+
+
+ {data?.message?.map((message) => {
+ return (
+
+ )
+ })}
+
+ >
+ )
+}
\ No newline at end of file
diff --git a/frontend/src/components/feature/pinned-messages/ViewPinnedMessagesButton.tsx b/frontend/src/components/feature/pinned-messages/ViewPinnedMessagesButton.tsx
new file mode 100644
index 000000000..b44c23dc2
--- /dev/null
+++ b/frontend/src/components/feature/pinned-messages/ViewPinnedMessagesButton.tsx
@@ -0,0 +1,38 @@
+import { Button, Dialog } from '@radix-ui/themes'
+import { RiPushpinLine } from 'react-icons/ri'
+import { useState } from 'react'
+import { DIALOG_CONTENT_CLASS } from '@/utils/layout/dialog'
+import { PinnedMessageModalContent } from './PinnedMessageModalContent'
+
+interface ViewPinnedMessagesButtonProps {
+ pinnedMessagesString: string
+}
+
+export const ViewPinnedMessagesButton = ({ pinnedMessagesString }: ViewPinnedMessagesButtonProps) => {
+
+ const pinnedMessages = pinnedMessagesString ? pinnedMessagesString.split('\n').length : 0
+
+ const [open, setOpen] = useState(false)
+
+ const onClose = () => {
+ setOpen(false)
+ }
+
+ if (!pinnedMessages) {
+ return null
+ }
+
+ return (
+
+
+
+
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/frontend/src/types/Raven/RavenPinnedMessages.ts b/frontend/src/types/Raven/RavenPinnedMessages.ts
new file mode 100644
index 000000000..aea403467
--- /dev/null
+++ b/frontend/src/types/Raven/RavenPinnedMessages.ts
@@ -0,0 +1,15 @@
+
+export interface RavenPinnedMessages{
+ name: string
+ creation: string
+ modified: string
+ owner: string
+ modified_by: string
+ docstatus: 0 | 1 | 2
+ parent?: string
+ parentfield?: string
+ parenttype?: string
+ idx?: number
+ /** Message ID : Link - Raven Message */
+ message_id: string
+}
\ No newline at end of file
diff --git a/frontend/src/types/RavenChannelManagement/RavenChannel.ts b/frontend/src/types/RavenChannelManagement/RavenChannel.ts
index ac568500a..d46502a9f 100644
--- a/frontend/src/types/RavenChannelManagement/RavenChannel.ts
+++ b/frontend/src/types/RavenChannelManagement/RavenChannel.ts
@@ -1,3 +1,4 @@
+import { RavenPinnedMessages } from '../Raven/RavenPinnedMessages'
export interface RavenChannel{
creation: string
@@ -38,6 +39,10 @@ export interface RavenChannel{
last_message_timestamp?: string
/** Last Message Details : JSON */
last_message_details?: any
+ /** Pinned Messages : Table - Raven Pinned Messages */
+ pinned_messages?: RavenPinnedMessages[]
+ /** Pinned Messages String : Small Text */
+ pinned_messages_string?: string
/** Is AI Thread : Check */
is_ai_thread?: 0 | 1
/** OpenAI Thread ID : Data */
diff --git a/frontend/src/utils/channel/ChannelListProvider.tsx b/frontend/src/utils/channel/ChannelListProvider.tsx
index 88f22f155..cf1af4d11 100644
--- a/frontend/src/utils/channel/ChannelListProvider.tsx
+++ b/frontend/src/utils/channel/ChannelListProvider.tsx
@@ -1,10 +1,10 @@
import { FrappeConfig, FrappeContext, FrappeError, useFrappeDocTypeEventListener, useFrappeGetCall } from 'frappe-react-sdk'
import { PropsWithChildren, createContext, useContext, useMemo } from 'react'
import { KeyedMutator } from 'swr'
-import { RavenChannel } from '../../../../types/RavenChannelManagement/RavenChannel'
import { useSWRConfig } from 'frappe-react-sdk'
import { toast } from 'sonner'
import { getErrorMessage } from '@/components/layout/AlertBanner/ErrorBanner'
+import { RavenChannel } from '@/types/RavenChannelManagement/RavenChannel'
export type UnreadChannelCountItem = { name: string, user_id?: string, unread_count: number, is_direct_message: 0 | 1 }
@@ -16,7 +16,7 @@ export type UnreadCountData = {
export type ChannelListItem = Pick
+ 'is_archived' | 'creation' | 'owner' | 'last_message_details' | 'last_message_timestamp' | 'workspace' | 'pinned_messages_string'>
export interface DMChannelListItem extends ChannelListItem {
peer_user_id: string,
diff --git a/raven/api/raven_channel.py b/raven/api/raven_channel.py
index 5dcb023ee..29d140efe 100644
--- a/raven/api/raven_channel.py
+++ b/raven/api/raven_channel.py
@@ -62,6 +62,7 @@ def get_channel_list(hide_archived=False):
channel.owner,
channel.last_message_timestamp,
channel.last_message_details,
+ channel.pinned_messages_string,
channel.workspace,
)
.distinct()
@@ -221,6 +222,39 @@ def leave_channel(channel_id):
return "Ok"
+@frappe.whitelist()
+def toggle_pin_message(channel_id, message_id):
+ """
+ Toggle pin/unpin a message in a channel.
+ """
+ channel = frappe.get_doc("Raven Channel", channel_id)
+
+ pinned_message = None
+
+ # Check whether the message exists in the channel
+ message_exists = frappe.db.get_value("Raven Message", message_id, "channel_id") == channel_id
+
+ if not message_exists:
+ frappe.throw(_("Message does not exist in this channel"))
+
+ # Check if the message is already pinned
+ for pm in channel.pinned_messages:
+ if pm.message_id == message_id:
+ pinned_message = pm
+ break
+
+ if pinned_message:
+ # Unpin the message
+ channel.remove(pinned_message)
+ else:
+ # Pin the message if it's not pinned
+ channel.append("pinned_messages", {"message_id": message_id})
+
+ channel.save()
+
+ return "Ok"
+
+
@frappe.whitelist()
def mark_all_messages_as_read(channel_ids: list):
"""
diff --git a/raven/api/raven_message.py b/raven/api/raven_message.py
index 7b64d5b18..3d7660ee8 100644
--- a/raven/api/raven_message.py
+++ b/raven/api/raven_message.py
@@ -120,6 +120,43 @@ def save_message(message_id, add=False):
return "message saved"
+@frappe.whitelist()
+def get_pinned_messages(channel_id):
+
+ # check if the user has permission to view the channel
+ frappe.has_permission("Raven Channel", doc=channel_id, ptype="read", throw=True)
+
+ pinnedMessagesString = frappe.db.get_value("Raven Channel", channel_id, "pinned_messages_string")
+ pinnedMessages = pinnedMessagesString.split("\n") if pinnedMessagesString else []
+
+ return frappe.db.get_all(
+ "Raven Message",
+ filters={"name": ["in", pinnedMessages]},
+ fields=[
+ "name",
+ "owner",
+ "creation",
+ "text",
+ "file",
+ "message_type",
+ "message_reactions",
+ "_liked_by",
+ "channel_id",
+ "thumbnail_width",
+ "thumbnail_height",
+ "file_thumbnail",
+ "link_doctype",
+ "link_document",
+ "replied_message_details",
+ "content",
+ "is_edited",
+ "is_thread",
+ "is_forwarded",
+ ],
+ order_by="creation asc",
+ )
+
+
@frappe.whitelist()
def get_saved_messages():
"""
diff --git a/raven/raven/doctype/raven_pinned_messages/__init__.py b/raven/raven/doctype/raven_pinned_messages/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/raven/raven/doctype/raven_pinned_messages/raven_pinned_messages.json b/raven/raven/doctype/raven_pinned_messages/raven_pinned_messages.json
new file mode 100644
index 000000000..f62495720
--- /dev/null
+++ b/raven/raven/doctype/raven_pinned_messages/raven_pinned_messages.json
@@ -0,0 +1,33 @@
+{
+ "actions": [],
+ "allow_rename": 1,
+ "creation": "2024-10-13 16:40:20.096165",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "message_id"
+ ],
+ "fields": [
+ {
+ "fieldname": "message_id",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Message ID",
+ "options": "Raven Message",
+ "reqd": 1
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2024-10-13 16:41:54.688859",
+ "modified_by": "Administrator",
+ "module": "Raven",
+ "name": "Raven Pinned Messages",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "creation",
+ "sort_order": "DESC",
+ "states": []
+}
\ No newline at end of file
diff --git a/raven/raven/doctype/raven_pinned_messages/raven_pinned_messages.py b/raven/raven/doctype/raven_pinned_messages/raven_pinned_messages.py
new file mode 100644
index 000000000..20b66611c
--- /dev/null
+++ b/raven/raven/doctype/raven_pinned_messages/raven_pinned_messages.py
@@ -0,0 +1,23 @@
+# Copyright (c) 2024, The Commit Company (Algocode Technologies Pvt. Ltd.) and contributors
+# For license information, please see license.txt
+
+# import frappe
+from frappe.model.document import Document
+
+
+class RavenPinnedMessages(Document):
+ # begin: auto-generated types
+ # This code is auto-generated. Do not modify anything in this block.
+
+ from typing import TYPE_CHECKING
+
+ if TYPE_CHECKING:
+ from frappe.types import DF
+
+ message_id: DF.Link
+ parent: DF.Data
+ parentfield: DF.Data
+ parenttype: DF.Data
+ # end: auto-generated types
+
+ pass
diff --git a/raven/raven_channel_management/doctype/raven_channel/raven_channel.json b/raven/raven_channel_management/doctype/raven_channel/raven_channel.json
index f6b62654f..10ff630d8 100644
--- a/raven/raven_channel_management/doctype/raven_channel/raven_channel.json
+++ b/raven/raven_channel_management/doctype/raven_channel/raven_channel.json
@@ -27,6 +27,9 @@
"last_message_timestamp",
"column_break_eckt",
"last_message_details",
+ "section_break_acpc",
+ "pinned_messages",
+ "pinned_messages_string",
"ai_tab",
"is_ai_thread",
"openai_thread_id",
@@ -174,6 +177,21 @@
"options": "Raven Bot",
"read_only": 1
},
+ {
+ "fieldname": "section_break_acpc",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "pinned_messages",
+ "fieldtype": "Table",
+ "label": "Pinned Messages",
+ "options": "Raven Pinned Messages"
+ },
+ {
+ "fieldname": "pinned_messages_string",
+ "fieldtype": "Small Text",
+ "label": "Pinned Messages String"
+ },
{
"fieldname": "workspace",
"fieldtype": "Link",
diff --git a/raven/raven_channel_management/doctype/raven_channel/raven_channel.py b/raven/raven_channel_management/doctype/raven_channel/raven_channel.py
index d80a8a211..62b170f48 100644
--- a/raven/raven_channel_management/doctype/raven_channel/raven_channel.py
+++ b/raven/raven_channel_management/doctype/raven_channel/raven_channel.py
@@ -17,6 +17,8 @@ class RavenChannel(Document):
if TYPE_CHECKING:
from frappe.types import DF
+ from raven.raven.doctype.raven_pinned_messages.raven_pinned_messages import RavenPinnedMessages
+
channel_description: DF.SmallText | None
channel_name: DF.Data
is_ai_thread: DF.Check
@@ -31,6 +33,8 @@ class RavenChannel(Document):
linked_doctype: DF.Link | None
linked_document: DF.DynamicLink | None
openai_thread_id: DF.Data | None
+ pinned_messages: DF.Table[RavenPinnedMessages]
+ pinned_messages_string: DF.SmallText | None
thread_bot: DF.Link | None
type: DF.Literal["Private", "Public", "Open"]
workspace: DF.Link | None
@@ -169,6 +173,11 @@ def before_validate(self):
if len(workspaces) == 1:
self.workspace = workspaces[0].name
+ self.set_pinned_messages_string()
+
+ def set_pinned_messages_string(self):
+ self.pinned_messages_string = "\n".join([message.message_id for message in self.pinned_messages])
+
def add_members(self, members, is_admin=0):
# members is a list of Raven User IDs
for member in members:
diff --git a/raven/raven_messaging/doctype/raven_message/raven_message.py b/raven/raven_messaging/doctype/raven_message/raven_message.py
index 2cea95007..d72361f38 100644
--- a/raven/raven_messaging/doctype/raven_message/raven_message.py
+++ b/raven/raven_messaging/doctype/raven_message/raven_message.py
@@ -584,6 +584,21 @@ def on_trash(self):
thread_channel_doc = frappe.get_doc("Raven Channel", self.name)
thread_channel_doc.delete(ignore_permissions=True)
+ # delete the pinned message
+ is_pinned = frappe.get_all(
+ "Raven Pinned Messages", {"message_id": self.name, "parent": self.channel_id}
+ )
+ if is_pinned:
+ channel_doc = frappe.get_doc("Raven Channel", self.channel_id)
+ pinned_row = None
+ for pinned_message in channel_doc.pinned_messages:
+ if pinned_message.message_id == self.name:
+ pinned_row = pinned_message
+ break
+ if pinned_row:
+ channel_doc.remove(pinned_row)
+ channel_doc.save()
+
def on_doctype_update():
"""
diff --git a/types/Messaging/Message.ts b/types/Messaging/Message.ts
index 0a50a860a..ee079e1b2 100644
--- a/types/Messaging/Message.ts
+++ b/types/Messaging/Message.ts
@@ -23,6 +23,7 @@ export interface BaseMessage {
bot?: string,
hide_link_preview?: 1 | 0,
is_thread: 1 | 0,
+ is_pinned: 1 | 0,
}
export interface FileMessage extends BaseMessage {