From 1fab115875ea63711edb3a7a42cd68cadf388c3d Mon Sep 17 00:00:00 2001 From: prathameshkurunkar7 Date: Sat, 4 Apr 2026 13:02:17 +0530 Subject: [PATCH 1/8] fix(mobile): improve text overflow handling in ReplyMessageBox --- .../features/chat/ChatMessage/Renderers/ReplyMessageBox.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/mobile/components/features/chat/ChatMessage/Renderers/ReplyMessageBox.tsx b/apps/mobile/components/features/chat/ChatMessage/Renderers/ReplyMessageBox.tsx index 23b2f5258..d66beedf1 100644 --- a/apps/mobile/components/features/chat/ChatMessage/Renderers/ReplyMessageBox.tsx +++ b/apps/mobile/components/features/chat/ChatMessage/Renderers/ReplyMessageBox.tsx @@ -39,7 +39,7 @@ const ReplyMessageBox = ({ message, onPress }: ReplyMessageBoxProps) => { return ( - + Poll: {replyMessageDetails.content?.split("\n")?.[0]} @@ -49,7 +49,7 @@ const ReplyMessageBox = ({ message, onPress }: ReplyMessageBoxProps) => { return default: - return + return {replyMessageDetails.content} } @@ -122,4 +122,4 @@ const ImageFileReplyBlock = ({ file, messageType, owner }: { file: string, messa ) } -export default ReplyMessageBox \ No newline at end of file +export default ReplyMessageBox From 76748a7c602bb306706653126484b49350504026 Mon Sep 17 00:00:00 2001 From: prathameshkurunkar7 Date: Sat, 4 Apr 2026 13:02:36 +0530 Subject: [PATCH 2/8] feat(mobile): add workspace joining functionality to WorkspaceSwitcher --- .../features/workspaces/WorkspaceSwitcher.tsx | 74 +++++++++++++++++-- 1 file changed, 66 insertions(+), 8 deletions(-) diff --git a/apps/mobile/components/features/workspaces/WorkspaceSwitcher.tsx b/apps/mobile/components/features/workspaces/WorkspaceSwitcher.tsx index 3cb31e7b2..7eda65965 100644 --- a/apps/mobile/components/features/workspaces/WorkspaceSwitcher.tsx +++ b/apps/mobile/components/features/workspaces/WorkspaceSwitcher.tsx @@ -15,6 +15,10 @@ import SiteSwitcher from '../auth/SiteSwitcher' import { getSiteNameFromUrl } from '@raven/lib/utils/operations' import ServerIcon from '@assets/icons/ServerIcon.svg' import AddSite from '../auth/AddSite' +import { FrappeError, useFrappePostCall, useSWRConfig } from 'frappe-react-sdk' +import { toast } from 'sonner-native' +import { getErrorMessage } from '@components/common/ErrorBanner' +import { ActivityIndicator } from '@components/nativewindui/ActivityIndicator' const WorkspaceSwitcher = ({ workspace, setWorkspace }: { workspace: string, setWorkspace: (workspace: string) => Promise }) => { @@ -108,6 +112,9 @@ interface SelectWorkspaceSheetProps { const SelectWorkspaceSheet = ({ selectedWorkspace, workspaces, setWorkspace }: SelectWorkspaceSheetProps) => { + const { call: joinWorkspace, loading: joiningWorkspace } = useFrappePostCall('raven.api.workspaces.join_workspace') + const { mutate } = useSWRConfig() + const { myWorkspaces, otherWorkspaces } = useMemo(() => { const myWorkspaces: Workspace[] = [] const otherWorkspaces: Workspace[] = [] @@ -127,6 +134,26 @@ const SelectWorkspaceSheet = ({ selectedWorkspace, workspaces, setWorkspace }: S return { myWorkspaces, otherWorkspaces } }, [workspaces, selectedWorkspace]) + const handleJoinOtherWorkspace = useCallback( + (workspaceName: string) => { + const displayName = + workspaces.find((w) => w.name === workspaceName)?.workspace_name ?? workspaceName + + joinWorkspace({ workspace: workspaceName }) + .then(() => Promise.all([mutate('workspaces_list'), mutate('channel_list')])) + .then(() => setWorkspace(workspaceName)) + .then(() => { + toast.success(`You have joined ${displayName}.`) + }) + .catch((error: unknown) => { + toast.error( + getErrorMessage(error as FrappeError) || 'Failed to join the workspace.' + ) + }) + }, + [joinWorkspace, setWorkspace, workspaces] + ) + const siteInfo = useSiteContext() const urlWithoutProtocol = useMemo(() => { @@ -163,6 +190,8 @@ const SelectWorkspaceSheet = ({ selectedWorkspace, workspaces, setWorkspace }: S workspace={workspace} setWorkspace={setWorkspace} isOtherWorkspace + isJoining={joiningWorkspace} + onJoinOtherWorkspace={handleJoinOtherWorkspace} isLast={index === otherWorkspaces.length - 1} /> ))} @@ -173,18 +202,45 @@ const SelectWorkspaceSheet = ({ selectedWorkspace, workspaces, setWorkspace }: S ) } -const WorkspaceRow = ({ workspace, isLast, setWorkspace, isOtherWorkspace = false }: { workspace: Workspace, isLast: boolean, setWorkspace: (workspace: string) => Promise, isOtherWorkspace?: boolean }) => { +type WorkspaceRowProps = { + workspace: Workspace + isLast: boolean + setWorkspace: (workspace: string) => Promise + isOtherWorkspace?: boolean + /** True while this row's join request is in flight */ + isJoining?: boolean + onJoinOtherWorkspace?: (workspaceName: string) => void +} + +const WorkspaceRow = ({ + workspace, + isLast, + setWorkspace, + isOtherWorkspace = false, + isJoining = false, + onJoinOtherWorkspace, +}: WorkspaceRowProps) => { const { colors } = useColorScheme() - const onClick = () => { + const onPress = () => { + if (isOtherWorkspace && onJoinOtherWorkspace) { + void onJoinOtherWorkspace(workspace.name) + return + } if (!isOtherWorkspace) { - setWorkspace(workspace.name) + void setWorkspace(workspace.name) } } + const disabled = isOtherWorkspace && isJoining + return ( - - + + {workspace.workspace_name} {workspace.type} - {workspace.isSelected && + {isJoining ? ( + + ) : workspace.isSelected ? ( - } + ) : null} {!isLast && } @@ -216,4 +274,4 @@ const getLogo = (workspace: WorkspaceFields) => { return logo } -export default WorkspaceSwitcher \ No newline at end of file +export default WorkspaceSwitcher From a94bca98a1e7154cc0d773f60e368c0655a8651a Mon Sep 17 00:00:00 2001 From: Aditya Patil Date: Wed, 8 Apr 2026 18:00:07 +0530 Subject: [PATCH 3/8] fix: workspace unread badge overflow --- frontend/src/components/layout/Sidebar/WorkspacesSidebar.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/layout/Sidebar/WorkspacesSidebar.tsx b/frontend/src/components/layout/Sidebar/WorkspacesSidebar.tsx index 215a96ee4..78a4c22be 100644 --- a/frontend/src/components/layout/Sidebar/WorkspacesSidebar.tsx +++ b/frontend/src/components/layout/Sidebar/WorkspacesSidebar.tsx @@ -102,8 +102,8 @@ const WorkspaceItem = ({ workspace }: { workspace: WorkspaceFields & { unread_co {workspace.unread_count > 0 && - - {workspace.unread_count} + + {workspace.unread_count > 99 ? '99+' : workspace.unread_count} } From 1b55ecd83b76e31ff8c0e843d6cd3dcfa8ffe520 Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Thu, 9 Apr 2026 21:58:26 +0200 Subject: [PATCH 4/8] fix: prevent RecursionError when caching link previews --- raven/api/preview_links.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/raven/api/preview_links.py b/raven/api/preview_links.py index 19d0520a2..69bccce57 100644 --- a/raven/api/preview_links.py +++ b/raven/api/preview_links.py @@ -60,12 +60,12 @@ def get_preview_link(urls: list[str] | str): # TODO: We need to replace these special characters with the actual emojis data = { - "title": preview.title, - "description": preview.description, - "image": preview.image, - "force_title": preview.force_title, - "absolute_image": preview.absolute_image, - "site_name": preview.site_name, + "title": str(preview.title or ""), + "description": str(preview.description or ""), + "image": str(preview.image or ""), + "force_title": str(preview.force_title or ""), + "absolute_image": str(preview.absolute_image or ""), + "site_name": str(preview.site_name or ""), } frappe.cache().set_value(url, data) message_links.append(data) From 4e558a47a835905864e1f45580a0a534ec559972 Mon Sep 17 00:00:00 2001 From: Prathamesh Kurunkar <59260326+prathameshkurunkar7@users.noreply.github.com> Date: Fri, 10 Apr 2026 11:43:05 +0530 Subject: [PATCH 5/8] fix: save message not working correctly (#2118) --- raven/api/raven_message.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/raven/api/raven_message.py b/raven/api/raven_message.py index 7d0c630d5..6311b3862 100644 --- a/raven/api/raven_message.py +++ b/raven/api/raven_message.py @@ -108,9 +108,9 @@ def save_message(message_id: str, add: str | bool = False): """ Save the message as a bookmark """ - - if isinstance(add, str): - add = add.lower() == "yes" or add == "1" + # no need to check if arg add is string, as Yes is being passed, which is what is expected by toggle_like + if isinstance(add, bool): + add = "Yes" if add else "No" if not frappe.has_permission(doctype="Raven Message", doc=message_id, ptype="read"): frappe.throw(_("You don't have permission to save this message"), frappe.PermissionError) From d1a9df6773349a6d86ba6e530dc93923d05b32fa Mon Sep 17 00:00:00 2001 From: Prathamesh Kurunkar <59260326+prathameshkurunkar7@users.noreply.github.com> Date: Fri, 17 Apr 2026 21:33:59 +0530 Subject: [PATCH 6/8] fix(notifications)!: improve notification handling in service worker (#2126) --- frontend/public/sw.js | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/frontend/public/sw.js b/frontend/public/sw.js index d9f4fd688..4dadba5f4 100644 --- a/frontend/public/sw.js +++ b/frontend/public/sw.js @@ -21,21 +21,25 @@ try { } onBackgroundMessage(messaging, (payload) => { - const notificationTitle = payload.notification.title + const data = payload.data || {} + const notification = payload.notification || {} + + const notificationTitle = data.title || notification.title let notificationOptions = { - body: payload.notification.body || "", + body: data.body || notification.body || "", } - if (payload.data.image) { - notificationOptions["icon"] = payload.data.image + + if (data.image) { + notificationOptions["icon"] = data.image } - if (payload.data.creation) { - notificationOptions["timestamp"] = payload.data.creation + if (data.creation) { + notificationOptions["timestamp"] = data.creation } - let url = `${payload.data.base_url}/raven/channel/${payload.data.channel_id}` + let url = `${data.base_url}/raven/channel/${data.channel_id}` - if (payload.data.message_url) { - url = payload.data.message_url + if (data.message_url) { + url = data.message_url } if (isChrome()) { @@ -68,4 +72,4 @@ try { self.skipWaiting() clientsClaim() -console.log("Service Worker Initialized") \ No newline at end of file +console.log("Service Worker Initialized") From 2f261980abf6873db3abf5a6edf866147967583a Mon Sep 17 00:00:00 2001 From: Prathamesh Kurunkar <59260326+prathameshkurunkar7@users.noreply.github.com> Date: Fri, 17 Apr 2026 23:26:09 +0530 Subject: [PATCH 7/8] fix(notifications): update onMessage show notification handler (#2127) --- frontend/src/utils/pushNotifications.ts | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/frontend/src/utils/pushNotifications.ts b/frontend/src/utils/pushNotifications.ts index 1aed72cdb..8005e1380 100644 --- a/frontend/src/utils/pushNotifications.ts +++ b/frontend/src/utils/pushNotifications.ts @@ -6,23 +6,27 @@ export const showNotification = (payload: any) => { const registration = window.frappePushNotification.serviceWorkerRegistration if (!registration) return - const notificationTitle = payload?.notification?.title + const data = payload?.data ?? {} + const notification = payload?.notification ?? {} + + + const notificationTitle = data.title || notification.title const notificationOptions = { body: payload?.notification?.body || "", } - if (payload?.data?.image) { + if (data.image) { // @ts-ignore - notificationOptions["icon"] = payload.data.image + notificationOptions["icon"] = data.image } - if (payload.data.creation) { + if (data.creation) { // @ts-ignore - notificationOptions["timestamp"] = payload.data.creation + notificationOptions["timestamp"] = data.creation } - let url = `${payload.data.base_url}/raven/channel/${payload.data.channel_id}` + let url = `${data.base_url}/raven/channel/${data.channel_id}` - if (payload.data.message_url) { - url = payload.data.message_url + if (data.message_url) { + url = data.message_url } if (isChrome()) { @@ -31,7 +35,7 @@ export const showNotification = (payload: any) => { url: url, } } else { - if (payload?.data?.click_action) { + if (data.click_action) { // @ts-ignore notificationOptions["actions"] = [ { @@ -43,4 +47,4 @@ export const showNotification = (payload: any) => { } registration.showNotification(notificationTitle, notificationOptions) -} \ No newline at end of file +} From ae4d2cb2e4ea4d223a967aaa423fbcdb6365a9c7 Mon Sep 17 00:00:00 2001 From: Prathamesh Kurunkar <59260326+prathameshkurunkar7@users.noreply.github.com> Date: Fri, 17 Apr 2026 23:30:52 +0530 Subject: [PATCH 8/8] chore: bump version to 2.8.11 across all packages (#2128) --- frontend/package.json | 2 +- package.json | 2 +- raven/__init__.py | 2 +- raven/package.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index a122df284..09be607b2 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -2,7 +2,7 @@ "name": "raven-web", "private": true, "license": "AGPL-3.0-only", - "version": "2.8.10", + "version": "2.8.11", "type": "module", "scripts": { "dev": "vite", diff --git a/package.json b/package.json index 58ce637e5..de5b6fa16 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "raven", - "version": "2.8.10", + "version": "2.8.11", "description": "Messaging Application", "workspaces": [ "frontend", diff --git a/raven/__init__.py b/raven/__init__.py index 0ad170f77..6b912931f 100644 --- a/raven/__init__.py +++ b/raven/__init__.py @@ -1,4 +1,4 @@ -__version__ = "2.8.10" +__version__ = "2.8.11" from raven.raven_integrations.doctype.raven_incoming_webhook.raven_incoming_webhook import ( # noqa handle_incoming_webhook as webhook, diff --git a/raven/package.json b/raven/package.json index fcf209f2d..3e73d5ba4 100644 --- a/raven/package.json +++ b/raven/package.json @@ -1,6 +1,6 @@ { "name": "raven-app", - "version": "2.8.10", + "version": "2.8.11", "description": "", "main": "index.js", "scripts": {