Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: webhooks #665

Closed
wants to merge 47 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
96194c3
feat: Raven Bot Doctype Setup
TITANiumRox Jan 19, 2024
4da8451
fix: Not assuming User as Human
TITANiumRox Jan 19, 2024
e7e2c63
Merge pull request #641 from The-Commit-Company/develop
sumitjain236 Jan 25, 2024
560336d
Merge pull request #642 from The-Commit-Company/integration
sumitjain236 Jan 25, 2024
8fd9782
feat: add route for Settings page
yjane99 Jan 25, 2024
287f14b
feat: Sidebar for Settings page (basic routes and layout)
yjane99 Jan 25, 2024
02c0097
Merge pull request #643 from The-Commit-Company/rav-37-settings-page-…
yjane99 Jan 25, 2024
bd03e2c
style: cursor pointer
yjane99 Jan 25, 2024
5366714
fix: hide 'Settings' options from Footer menu
yjane99 Jan 25, 2024
1bf1ac1
Merge pull request #644 from The-Commit-Company/rav-37-settings-page-…
yjane99 Jan 25, 2024
cd46352
Merge pull request #645 from The-Commit-Company/integration
sumitjain236 Jan 25, 2024
0264a6c
Merge branch 'integration' into rav-39-raven-bot-doctype-setup
TITANiumRox Feb 2, 2024
3e3a850
Merge pull request #637 from The-Commit-Company/rav-39-raven-bot-doct…
TITANiumRox Feb 2, 2024
78b66ee
fix: updated Raven Message doctype
TITANiumRox Feb 2, 2024
7d35761
Merge branch 'integration' into rav-39-raven-bot-doctype-setup
TITANiumRox Feb 2, 2024
fe713f5
Merge pull request #656 from The-Commit-Company/rav-39-raven-bot-doct…
TITANiumRox Feb 2, 2024
d21b0b1
feat:type files
sumitjain236 Feb 12, 2024
9b5b88b
feat:webhook form
sumitjain236 Feb 12, 2024
73fac17
feat:webhook list
sumitjain236 Feb 12, 2024
68aceb6
feat:create and view webhook
sumitjain236 Feb 12, 2024
9743a3f
feat: add routes and links
yjane99 Feb 12, 2024
84d8ecf
feat: common delete Alert for Integration pages
yjane99 Feb 12, 2024
53e7384
feat: API events pages
yjane99 Feb 12, 2024
ab5c049
feat: DocType Events pages
yjane99 Feb 12, 2024
2f58e75
feat: Scheduler Events pages
yjane99 Feb 12, 2024
85201b5
feat:removed useEditor
sumitjain236 Feb 13, 2024
988262b
feat: Raven Integrations module w/ wrapper doctype for Scheduler Events
yjane99 Feb 23, 2024
eb41335
feat: Raven Scheduler Event DocType.
yjane99 Feb 23, 2024
18d949a
Merge branch 'rav-raven-scheduler-event-doctype-setup' into rav-69-se…
yjane99 Feb 23, 2024
6ab7306
Merge pull request #705 from The-Commit-Company/rav-69-server-scripts…
yjane99 Feb 23, 2024
a24bd31
feat:raven Integrations module created
sumitjain236 Feb 23, 2024
028b0ad
feat:Raven Webhook wrapper on Webhook
sumitjain236 Feb 23, 2024
406722c
feat:Raven Webhook Forms
sumitjain236 Feb 23, 2024
2e7b185
Merge pull request #713 from The-Commit-Company/develop
sumitjain236 Feb 23, 2024
c551b8e
feat:raven webhook controller methods
sumitjain236 Feb 23, 2024
150ff4a
feat:User,Channel Provider on Settings page
sumitjain236 Feb 23, 2024
337b801
feat:User, Channel and Channel Type list on Webhook Form
sumitjain236 Feb 23, 2024
24c9862
feat:User, Channel and Channel Type Select Dropdown
sumitjain236 Feb 23, 2024
45ab515
feat:unique key and header
sumitjain236 Feb 23, 2024
8157da4
feat:Preview of Response
sumitjain236 Feb 23, 2024
c3e06d9
Merge branch 'rav-raven-scheduler-event-doctype-setup' into rav-55-we…
sumitjain236 Mar 1, 2024
7d9a6a6
feat:removed unwanted files
sumitjain236 Mar 1, 2024
a65f2dc
fix:remove Delete Alert
sumitjain236 Mar 1, 2024
ca803bb
Merge branch 'develop' into rav-55-webhook-ui
sumitjain236 Mar 1, 2024
02e69ff
fix:imports
sumitjain236 Mar 1, 2024
5ca9a4b
fix:code overflow ouside code bock
sumitjain236 Mar 1, 2024
55855a0
Merge branch 'develop' into rav-55-webhook-ui
nikkothari22 Mar 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions mobile/src/types/Raven/RavenUser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,18 @@ export interface RavenUser {
parentfield?: string
parenttype?: string
idx?: number
/** Type : Select */
type: "User" | "Bot"
/** User : Link - User */
user: string
user?: string
/** Bot : Link - Raven Bot */
bot?: string
/** Full Name : Data */
full_name: string
full_name?: string
/** First Name : Data */
first_name?: string
/** User Image : Attach Image */
user_image?: string,
enabled: 0 | 1
user_image?: string
/** Enabled : Check */
enabled?: 0 | 1
}
25 changes: 25 additions & 0 deletions mobile/src/types/RavenBot/RavenBot.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

export interface RavenBot{
creation: string
name: string
modified: string
owner: string
modified_by: string
docstatus: 0 | 1 | 2
parent?: string
parentfield?: string
parenttype?: string
idx?: number
/** Bot Name : Data */
bot_name?: string
/** Description : Data */
description?: string
/** Image : Attach Image */
image?: string
/** Enabled : Check */
enabled?: 0 | 1
/** Is Standard : Check */
is_standard?: 0 | 1
/** Module : Link - Module Def */
module?: string
}
6 changes: 6 additions & 0 deletions mobile/src/types/RavenMessaging/RavenMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ export interface RavenMessage {
link_document?: string
/** Is Edited : Check */
is_edited?: 0 | 1
/** Is Bot Message : Check */
is_bot_message?: 0 | 1
/** Bot : Link - Raven User */
bot?: string
/** Content : Long Text */
content?: string
/** Mentions : Table - Raven Mention */
mentions?: RavenMention[]
}
25 changes: 18 additions & 7 deletions raven-app/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { FrappeProvider } from 'frappe-react-sdk'
import { Route, RouterProvider, createBrowserRouter, createRoutesFromElements } from 'react-router-dom'
import { Outlet, Route, RouterProvider, createBrowserRouter, createRoutesFromElements } from 'react-router-dom'
import { MainPage } from './pages/MainPage'
import { ProtectedRoute } from './utils/auth/ProtectedRoute'
import { UserProvider } from './utils/auth/UserProvider'
Expand All @@ -9,7 +9,10 @@ import { ThemeProvider } from './ThemeProvider'
import { Toaster } from './components/common/Toast/Toaster'
import { FullPageLoader } from './components/layout/Loaders'
import { useStickyState } from './hooks/useStickyState'

import { Settings } from './pages/settings/Settings'
import { CreateWebhook } from './components/feature/integrations/webhooks/CreateWebhook'
import ViewWebhook from './components/feature/integrations/webhooks/ViewWebhook'
import { WebhookList } from './components/feature/integrations/webhooks/WebhookList'

const router = createBrowserRouter(
createRoutesFromElements(
Expand All @@ -18,11 +21,19 @@ const router = createBrowserRouter(
<Route path='/login-with-email' lazy={() => import('@/pages/auth/LoginWithEmail')} />
<Route path='/signup' lazy={() => import('@/pages/auth/SignUp')} />
<Route path="/" element={<ProtectedRoute />}>
<Route index element={<ChannelRedirect />} />
<Route path="channel" element={<MainPage />} >
<Route index element={<ChannelRedirect />} />
<Route path="saved-messages" lazy={() => import('./components/feature/saved-messages/SavedMessages')} />
<Route path=":channelID" lazy={() => import('@/pages/ChatSpace')} />
<Route path="/" element={<ChannelRedirect />}>
<Route path="channel" element={<MainPage />} >
<Route index element={<ChannelRedirect />} />
<Route path="saved-messages" lazy={() => import('./components/feature/saved-messages/SavedMessages')} />
<Route path=":channelID" lazy={() => import('@/pages/ChatSpace')} />
</Route>
<Route path='settings' element={<Settings />}>
<Route path='integrations'>
<Route path='webhooks' element={<WebhookList />} />
<Route path='webhooks/create' element={<CreateWebhook />} />
<Route path='webhooks/:ID' element={<ViewWebhook />} />
</Route>
</Route>
</Route>
</Route>
</>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { Webhook } from '@/types/Integrations/Webhook'
import { useFrappeCreateDoc } from 'frappe-react-sdk'
import { FormProvider, useForm } from 'react-hook-form'
import { useNavigate } from 'react-router-dom'
import { Button, Flex, Separator, Text } from '@radix-ui/themes'
import { BiChevronLeft } from 'react-icons/bi'
import { ErrorBanner } from '@/components/layout/AlertBanner'
import { WebhookForm } from './WebhookForm'
import { useToast } from '@/hooks/useToast'
import { RavenWebhook } from '@/types/RavenIntegrations/RavenWebhook'

export const CreateWebhook = () => {

const navigate = useNavigate()

const methods = useForm<RavenWebhook>({
defaultValues: {
enabled: 1,
timeout: 5
}
})
const { createDoc, loading, reset, error } = useFrappeCreateDoc()

const { toast } = useToast()

const onSubmit = (data: RavenWebhook) => {
createDoc('Raven Webhook', data)
.then((doc) => {
reset()
methods.reset()
toast({
title: "Webhook created successfully.",
variant: 'success',
})
return doc
}).then((doc) => {
navigate(`../webhooks/${doc.name}`)
})
}

return (
<Flex direction='column' gap='4' py='4' width={'100%'} height={'100%'} style={{
alignItems: 'center',
justifyContent: 'start',
minHeight: '100vh'
}}>
<Flex direction='column' gap='4' pt={'4'} width='100%' style={{
maxWidth: '700px'
}} >
<BackToList />
<Flex direction='column' gap='4' width='100%' px={'2'}>
<header>
<Text size='6' weight='bold'>Create Webhook</Text>
</header>
<Separator size='4' className={`bg-gray-4 dark:bg-gray-6`} />
<ErrorBanner error={error} />
<FormProvider {...methods}>
<form onSubmit={methods.handleSubmit(onSubmit)}>
<WebhookForm />
</form>
</FormProvider>
<Button onClick={methods.handleSubmit(onSubmit)} disabled={loading} variant='solid' style={{
alignSelf: 'flex-end'
}} >
Create Webhook
</Button>
</Flex>
</Flex>
</Flex>

)
}

export const BackToList = () => {

const navigate = useNavigate()

return (
<header>
<Flex
align='center'
gap={'1'}
className="cursor-pointer"
onClick={() => navigate('/settings/integrations/webhooks')}
>
<BiChevronLeft size={'18px'} color="gray" />
<Text as='span' size='1' weight={'medium'}>Back to the list</Text>
</Flex>
</header>
)
}
162 changes: 162 additions & 0 deletions raven-app/src/components/feature/integrations/webhooks/ViewWebhook.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
import { ErrorBanner } from "@/components/layout/AlertBanner"
import { FullPageLoader } from "@/components/layout/Loaders"
import { AlertDialog, Badge, Box, Button, DropdownMenu, Flex, IconButton, Separator, Text } from "@radix-ui/themes"
import { FrappeDoc, useFrappeGetDoc, useFrappeUpdateDoc } from "frappe-react-sdk"
import { FieldValues, FormProvider, useForm } from "react-hook-form"
import { useParams } from "react-router-dom"
import { KeyedMutator } from 'swr'
import { BackToList } from "./CreateWebhook"
import { WebhookForm } from "./WebhookForm"
import { useToast } from "@/hooks/useToast"
import { BiDotsVerticalRounded } from "react-icons/bi"
import { useState } from "react"
import { DIALOG_CONTENT_CLASS } from "@/utils/layout/dialog"
import { Loader } from "@/components/common/Loader"
import { RavenWebhook } from "@/types/RavenIntegrations/RavenWebhook"

const ViewWebhook = () => {

const { ID } = useParams<{ ID: string }>()
const { data, error, isLoading, mutate } = useFrappeGetDoc<RavenWebhook>('Raven Webhook', ID, undefined, {
shouldRetryOnError: false,
})

return (
<Box className='p-4'>
{isLoading && <FullPageLoader />}
{error && <ErrorBanner error={error} />}
{data && <ViewWebhookPage data={data} mutate={mutate} />}

</Box>
)
}

export default ViewWebhook
ViewWebhook.displayName = 'ViewWebhook'

export const ViewWebhookPage = ({ data, mutate }: { data: FrappeDoc<RavenWebhook>, mutate: KeyedMutator<FrappeDoc<RavenWebhook>> }) => {

const methods = useForm<RavenWebhook>({
defaultValues: {
...data,
docstatus: data.docstatus
}
})

const { updateDoc, loading, reset, error } = useFrappeUpdateDoc()

const { toast } = useToast()

const isDirty = methods.formState.isDirty

const onSubmit = async (data: FieldValues) => {
return updateDoc('Raven Webhook', data.name, data)
.then((doc) => {
toast({
title: "Webhook updated successfully.",
variant: 'success',
})
reset()
mutate()
if (doc) {
methods.reset({
...doc,
docstatus: doc.docstatus
})
}
})
}

const [open, setOpen] = useState(false)
const onClose = () => {
setOpen(false)
}

const onUpdateEnabled = () => {
updateDoc('Raven Webhook', data.name, {
enabled: !data.enabled
}).then((doc) => {
toast({
title: "Webhook updated successfully.",
variant: 'success',
})
reset()
mutate()
})
}

return (
<Flex direction='column' gap='4' py='4' width={'100%'} height={'100%'} style={{
alignItems: 'center',
justifyContent: 'start',
minHeight: '100vh'
}}>
<Flex direction='column' gap='4' pt={'4'} width='100%' style={{
maxWidth: '700px'
}} >
<BackToList />
<Flex direction='column' gap='4' width='100%' px={'2'}>
<Flex direction={'row'} gap={'2'} justify={'between'} align={'center'}>
<Flex direction={'row'} gap={'2'} align={'center'}>
<Text size='6' weight='bold'>{data?.name}</Text>
<Badge color={data.enabled ? 'green' : 'red'}>{data.enabled ? 'Enabled' : 'Disabled'}</Badge>
</Flex>
<DropdownMenu.Root>
<DropdownMenu.Trigger>
<IconButton aria-label='Options' color='gray' variant='ghost' style={{
// @ts-ignore
'--icon-button-ghost-padding': '0',
height: 'var(--base-button-height)',
width: 'var(--base-button-height)',
}}>
<BiDotsVerticalRounded />
</IconButton>
</DropdownMenu.Trigger>
<DropdownMenu.Content variant='soft'>
<DropdownMenu.Item color='gray' onClick={() => setOpen(true)} className="cursor-pointer">
{data.enabled ? 'Disable' : 'Enable'} Webhook
</DropdownMenu.Item>
</DropdownMenu.Content>
</DropdownMenu.Root>
</Flex>
<Separator size='4' className={`bg-gray-4 dark:bg-gray-6`} />
<ErrorBanner error={error} />
<FormProvider {...methods}>
<form onSubmit={methods.handleSubmit(onSubmit)}>
<WebhookForm isEdit={true} />
</form>
</FormProvider>
<Button onClick={methods.handleSubmit(onSubmit)} disabled={loading || !isDirty} variant='solid' style={{
alignSelf: 'flex-end'
}}>
Save Webhook
</Button>
</Flex>
</Flex>
<AlertDialog.Root open={open} onOpenChange={setOpen}>
<AlertDialog.Content className={DIALOG_CONTENT_CLASS}>
<AlertDialog.Title>
<Text>{data.enabled ? 'Disable' : 'Enable'} Webhook</Text>
</AlertDialog.Title>
<Flex direction={'column'} gap='2'>
<ErrorBanner error={error} />
<Text size='2'>Are you sure you want to {data.enabled ? 'disable' : 'enable'} this webhook?</Text>
</Flex>
<Flex gap="3" mt="4" justify="end">
<AlertDialog.Cancel>
<Button variant="soft" color="gray" onClick={onClose}>
Cancel
</Button>
</AlertDialog.Cancel>
<AlertDialog.Action>
<Button variant="solid" color="green" onClick={onUpdateEnabled} disabled={loading}>
{loading && <Loader />}
{loading ? "Updating" : data.enabled ? "Disable" : "Enable"}
</Button>
</AlertDialog.Action>
</Flex>
</AlertDialog.Content>
</AlertDialog.Root>
</Flex >
)
}
Loading
Loading