Skip to content

Commit

Permalink
Merge pull request #1055 from The-Commit-Company/develop
Browse files Browse the repository at this point in the history
Release v1.7.0
  • Loading branch information
nikkothari22 authored Sep 8, 2024
2 parents f06f031 + 58562fa commit 08e8035
Show file tree
Hide file tree
Showing 52 changed files with 1,092 additions and 168 deletions.
2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "raven-ui",
"private": true,
"license": "AGPL-3.0-only",
"version": "1.6.13",
"version": "1.7.0",
"type": "module",
"scripts": {
"dev": "vite",
Expand Down
7 changes: 6 additions & 1 deletion frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ const router = createBrowserRouter(
<Route path="/" element={<ChannelRedirect />}>
<Route path="channel" element={<MainPage />} >
<Route index element={<MobileTabsPage />} />
<Route path="threads" lazy={() => import('./components/feature/threads/Threads')}>
<Route path="thread/:threadID" lazy={() => import('./components/feature/threads/ThreadDrawer/ThreadDrawer')} />
</Route>
<Route path="saved-messages" lazy={() => import('./components/feature/saved-messages/SavedMessages')} />
<Route path="settings" lazy={() => import('./pages/settings/Settings')}>
<Route index element={<UserProfile />} />
Expand All @@ -31,7 +34,9 @@ const router = createBrowserRouter(
<Route path="frappe-hr" lazy={() => import('./pages/settings/Integrations/FrappeHR')} />
{/* <Route path="bots" lazy={() => import('./components/feature/userSettings/Bots')} /> */}
</Route>
<Route path=":channelID" lazy={() => import('@/pages/ChatSpace')} />
<Route path=":channelID" lazy={() => import('@/pages/ChatSpace')}>
<Route path="thread/:threadID" lazy={() => import('./components/feature/threads/ThreadDrawer/ThreadDrawer')} />
</Route>
</Route>
{/* <Route path='settings' lazy={() => import('./pages/settings/Settings')}>
<Route path='integrations'>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { useFrappeDeleteDoc, useFrappeGetCall } from 'frappe-react-sdk'
import { useFrappePostCall } from 'frappe-react-sdk'
import { Fragment, useContext } from 'react'
import { useNavigate } from 'react-router-dom'
import { UserContext } from '../../../../utils/auth/UserProvider'
import { ErrorBanner } from '../../../layout/AlertBanner'
import { ChannelListContext, ChannelListContextType, ChannelListItem } from '@/utils/channel/ChannelListProvider'
import { ChannelIcon } from '@/utils/layout/channelIcon'
Expand All @@ -19,22 +18,13 @@ interface LeaveChannelModalProps {

export const LeaveChannelModal = ({ onClose, channelData, isDrawer, closeDetailsModal }: LeaveChannelModalProps) => {

const { currentUser } = useContext(UserContext)
const { deleteDoc, loading: deletingDoc, error } = useFrappeDeleteDoc()
const { call, loading: deletingDoc, error } = useFrappePostCall('raven.api.raven_channel.leave_channel')
const navigate = useNavigate()

const { data: channelMember } = useFrappeGetCall<{ message: { name: string } }>('frappe.client.get_value', {
doctype: "Raven Channel Member",
filters: JSON.stringify({ channel_id: channelData?.name, user_id: currentUser }),
fieldname: JSON.stringify(["name"])
}, undefined, {
revalidateOnFocus: false
})

const { mutate } = useContext(ChannelListContext) as ChannelListContextType

const onSubmit = async () => {
return deleteDoc('Raven Channel Member', channelMember?.message.name).then(() => {
return call({ channel_id: channelData?.name }).then(() => {
toast('You have left the channel')
onClose()
mutate()
Expand Down
9 changes: 7 additions & 2 deletions frontend/src/components/feature/chat-header/ChannelHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,15 @@ export const ChannelHeader = ({ channelData }: ChannelHeaderProps) => {
<Link to='/channel' className="block bg-transparent hover:bg-transparent active:bg-transparent sm:hidden">
<BiChevronLeft size='24' className="block text-gray-12" />
</Link>
<Flex gap='4' align={'center'} className="group animate-fadein">
<Flex gap='4' align={'center'} className="group animate-fadein pr-4">
<Flex gap='1' align={'center'}>
<ChannelIcon type={channelData.type} size='18' />
<Heading className="text-lg sm:text-xl mb-0.5 text-ellipsis">{channelData.channel_name}</Heading>
<Heading
size={{
initial: '4',
sm: '5'
}}
className="mb-0.5 text-ellipsis line-clamp-1">{channelData.channel_name}</Heading>
</Flex>
<EditChannelNameButton channelID={channelData.name} channel_name={channelData.channel_name} channelType={channelData.type} disabled={channelData.is_archived == 1} />
</Flex>
Expand Down
10 changes: 8 additions & 2 deletions frontend/src/components/feature/chat-header/DMChannelHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { useGetUser } from "@/hooks/useGetUser"
import useIsUserOnLeave from "@/hooks/fetchers/useIsUserOnLeave"
import { UserContext } from "@/utils/auth/UserProvider"
import { replaceCurrentUserFromDMChannelName } from "@/utils/operations"
import { useIsDesktop } from "@/hooks/useMediaQuery"

interface DMChannelHeaderProps {
channelData: DMChannelListItem,
Expand Down Expand Up @@ -49,6 +50,8 @@ export const DMChannelHeader = ({ channelData }: DMChannelHeaderProps) => {

const userName = fullName ?? peer ?? replaceCurrentUserFromDMChannelName(channelData.channel_name, currentUser)

const isDesktop = useIsDesktop()

return (
<PageHeader>
<Flex gap='3' align='center'>
Expand All @@ -63,8 +66,11 @@ export const DMChannelHeader = ({ channelData }: DMChannelHeaderProps) => {
availabilityStatus={user?.availability_status}
skeletonSize='6'
isBot={isBot}
size='2' />
<Heading size='5'>
size={isDesktop ? '2' : '1'} />
<Heading size={{
initial: '4',
sm: '5'
}}>
<div className="flex items-center gap-2">
{userName}
{!user && <Badge color='gray' variant='soft'>Deleted</Badge>}
Expand Down
21 changes: 16 additions & 5 deletions frontend/src/components/feature/chat/ChatInput/Tiptap.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { BubbleMenu, EditorContent, EditorContext, Extension, ReactRenderer, useEditor } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'
import Underline from '@tiptap/extension-underline'
import React, { Suspense, lazy, useContext, useEffect } from 'react'
import React, { Suspense, lazy, useContext, useEffect, useMemo } from 'react'
import { TextFormattingMenu } from './TextFormattingMenu'
import Highlight from '@tiptap/extension-highlight'
import Link from '@tiptap/extension-link'
Expand Down Expand Up @@ -33,6 +33,7 @@ import { EmojiSuggestion } from './EmojiSuggestion'
import { useIsDesktop } from '@/hooks/useMediaQuery'
import { BiPlus } from 'react-icons/bi'
import clsx from 'clsx'
import { ChannelMembers } from '@/hooks/fetchers/useFetchChannelMembers'
const MobileInputActions = lazy(() => import('./MobileActions/MobileInputActions'))

const lowlight = createLowlight(common)
Expand All @@ -59,7 +60,8 @@ type TiptapEditorProps = {
onMessageSend: (message: string, json: any) => Promise<void>,
messageSending: boolean,
defaultText?: string,
replyMessage?: Message | null
replyMessage?: Message | null,
channelMembers?: ChannelMembers
}

export const UserMention = Mention.extend({
Expand All @@ -82,10 +84,19 @@ export const ChannelMention = Mention.extend({
}
})

const Tiptap = ({ isEdit, slotBefore, fileProps, onMessageSend, replyMessage, clearReplyMessage, placeholder = 'Type a message...', messageSending, sessionStorageKey = 'tiptap-editor', disableSessionStorage = false, defaultText = '' }: TiptapEditorProps) => {
const Tiptap = ({ isEdit, slotBefore, fileProps, onMessageSend, channelMembers, replyMessage, clearReplyMessage, placeholder = 'Type a message...', messageSending, sessionStorageKey = 'tiptap-editor', disableSessionStorage = false, defaultText = '' }: TiptapEditorProps) => {

const { enabledUsers } = useContext(UserListContext)

const channelMemberUsers = useMemo(() => {
if (channelMembers) {
// Filter enabled users to only include users that are in the channel
return enabledUsers.filter((user) => user.name in channelMembers)
} else {
return enabledUsers
}
}, [channelMembers, enabledUsers])

const { channels } = useContext(ChannelListContext) as ChannelListContextType

// this is a dummy extension only to create custom keydown behavior
Expand Down Expand Up @@ -301,7 +312,7 @@ const Tiptap = ({ isEdit, slotBefore, fileProps, onMessageSend, replyMessage, cl
},
suggestion: {
items: (query) => {
return enabledUsers.filter((user) => user.full_name.toLowerCase().startsWith(query.query.toLowerCase()))
return channelMemberUsers.filter((user) => user.full_name.toLowerCase().startsWith(query.query.toLowerCase()))
.slice(0, 10);
},
// char: '@',
Expand Down Expand Up @@ -466,7 +477,7 @@ const Tiptap = ({ isEdit, slotBefore, fileProps, onMessageSend, replyMessage, cl

if (isDesktop) {
return (
<Box className='border rounded-radius2 border-gray-300 dark:border-gray-500 dark:bg-gray-3 shadow-md'>
<Box className='border rounded-radius2 border-gray-300 dark:border-gray-500 dark:bg-gray-3'>
<EditorContext.Provider value={{ editor }}>
{slotBefore}
<EditorContent editor={editor} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Loader } from "@/components/common/Loader"
import { FiAlertTriangle } from "react-icons/fi"
import { Message } from "../../../../../../../types/Messaging/Message"
import { toast } from "sonner"
import { useNavigate } from "react-router-dom"

interface DeleteMessageModalProps {
onClose: (refresh?: boolean) => void,
Expand All @@ -14,19 +15,20 @@ interface DeleteMessageModalProps {
export const DeleteMessageModal = ({ onClose, message }: DeleteMessageModalProps) => {

const { deleteDoc, error, loading: deletingDoc } = useFrappeDeleteDoc()
const navigate = useNavigate()

const onSubmit = async () => {

return deleteDoc('Raven Message', message.name).then(() => {
toast('Message deleted')
message.is_thread && navigate(`/channel/${message.channel_id}`)
onClose()
})
}

return (
<>
<AlertDialog.Title>
Delete Message
Delete {message.is_thread ? 'Thread' : 'Message'}
</AlertDialog.Title>

<Flex direction={'column'} gap='2'>
Expand All @@ -40,7 +42,8 @@ export const DeleteMessageModal = ({ onClose, message }: DeleteMessageModalProps
</Callout.Root>

<ErrorBanner error={error} />
<Text size='3'>Are you sure you want to delete this message? It will be deleted for all users.</Text>
{message.is_thread ? <Text size='2'>This message is a thread, deleting it will delete all messages in the thread.</Text> :
<Text size='2'>Are you sure you want to delete this message? It will be deleted for all users.</Text>}
</Flex>

<Flex gap="3" mt="4" justify="end">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,13 @@ import { DIALOG_CONTENT_CLASS } from "@/utils/layout/dialog"
import { DeleteMessageModal } from "@/components/feature/chat/ChatMessage/ActionModals/DeleteMessageModal"

export const useDeleteMessage = () => {

const [message, setMessage] = useState<null | Message>(null)

const onClose = useCallback(() => {
setMessage(null)
}, [])



return {
message,
setDeleteMessage: setMessage,
Expand All @@ -27,8 +26,6 @@ interface DeleteMessageDialogProps {
onClose: () => void
}
export const DeleteMessageDialog = ({ message, isOpen, onClose }: DeleteMessageDialogProps) => {


return <AlertDialog.Root open={isOpen} onOpenChange={onClose}>
<AlertDialog.Content className={DIALOG_CONTENT_CLASS}>
{message &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,27 @@ import { getErrorMessage } from '@/components/layout/AlertBanner/ErrorBanner'
import { AiOutlineEdit } from 'react-icons/ai'
import { LuForward, LuReply } from 'react-icons/lu'
import { MdOutlineEmojiEmotions } from "react-icons/md";
import AttachFileToDocument from './AttachFileToDocument'
import { CreateThreadContextItem } from './QuickActions/CreateThreadButton'

export interface MessageContextMenuProps {
message?: Message | null,
onDelete: VoidFunction
onDelete: VoidFunction,
onEdit: VoidFunction,
onReply: VoidFunction,
onForward: VoidFunction,
onViewReaction?: VoidFunction
onAttachDocument: VoidFunction
onViewReaction?: VoidFunction,
onAttachDocument: VoidFunction,
showThreadButton?: boolean
}
export const MessageContextMenu = ({ message, onDelete, onEdit, onReply, onForward, onAttachDocument, onViewReaction }: MessageContextMenuProps) => {
export const MessageContextMenu = ({ message, onDelete, onEdit, onReply, onForward, showThreadButton, onAttachDocument, onViewReaction }: MessageContextMenuProps) => {

const copy = useMessageCopy(message)
const { currentUser } = useContext(UserContext)

const isOwner = currentUser === message?.owner;
const isOwner = currentUser === message?.owner && !message?.is_bot_message

const isReactionsAvailable = Object.keys(JSON.parse(message?.message_reactions ?? '{}')).length !== 0

return (
<ContextMenu.Content>
{message ? <>
Expand All @@ -49,7 +50,8 @@ export const MessageContextMenu = ({ message, onDelete, onEdit, onReply, onForwa
Forward
</Flex>
</ContextMenu.Item>
{/* <ContextMenu.Separator /> */}
{message && !message.is_thread && showThreadButton && <CreateThreadContextItem messageID={message.name} />}
<ContextMenu.Separator />
<ContextMenu.Group>
{message.message_type === 'Text' &&
<ContextMenu.Item onClick={copy}>
Expand Down Expand Up @@ -87,29 +89,10 @@ export const MessageContextMenu = ({ message, onDelete, onEdit, onReply, onForwa
</ContextMenu.Group>
}

</ContextMenu.Group>

<ContextMenu.Separator />
<ContextMenu.Group>

<SaveMessageAction message={message} />

{/* <ContextMenu.Item>
<Flex gap='2'>
<HiOutlineDocumentAdd size='18' />
Link with document
</Flex>
</ContextMenu.Item>
<ContextMenu.Item>
<Flex gap='2'>
<BiMailSend size='18' />
Send in an email
</Flex>
</ContextMenu.Item> */}

</ContextMenu.Group>

{isReactionsAvailable && <ContextMenu.Group>
<ContextMenu.Separator />
<ContextMenu.Item onClick={onViewReaction}>
Expand Down Expand Up @@ -173,7 +156,7 @@ const SaveMessageAction = ({ message }: { message: Message }) => {
<Flex gap='2'>
{!isSaved && <BiBookmarkPlus size='18' />}
{isSaved && <BiBookmarkMinus size='18' />}
{!isSaved ? "Save" : "Unsave"} message
{!isSaved ? "Save" : "Unsave"} Message

</Flex>
</ContextMenu.Item>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { useFrappePostCall } from 'frappe-react-sdk'
import { toast } from 'sonner'
import { QuickActionButton } from './QuickActionButton'
import { BiMessageDetail } from 'react-icons/bi'
import { useNavigate } from 'react-router-dom'
import { ContextMenu, Flex } from '@radix-ui/themes'

const useCreateThread = (messageID: string) => {
const navigate = useNavigate()

const { call } = useFrappePostCall('raven.api.threads.create_thread')
const handleCreateThread = () => {
call({ 'message_id': messageID }).then((res) => {
toast.success('Thread created successfully!')
navigate(`/channel/${res.message.channel_id}/thread/${res.message.thread_id}`)
}).catch(() => {
toast.error('Failed to create thread')
})
}

return handleCreateThread
}

export const CreateThreadActionButton = ({ messageID }: { messageID: string }) => {

const handleCreateThread = useCreateThread(messageID)

return (
<QuickActionButton
tooltip='Create a thread'
aria-label='Create a thread'
onClick={handleCreateThread}>
<BiMessageDetail size='16' />
</QuickActionButton>
)
}

export const CreateThreadContextItem = ({ messageID }: { messageID: string }) => {

const handleCreateThread = useCreateThread(messageID)

return <ContextMenu.Item onClick={handleCreateThread}>
<Flex gap='2' align='center'>
<BiMessageDetail size='18' />
Create Thread

</Flex>
</ContextMenu.Item>
}
Loading

0 comments on commit 08e8035

Please sign in to comment.