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

merging develop into main #1075

Merged
merged 87 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
c0b23bf
wip: AI integration
nikkothari22 Aug 28, 2024
a27024b
Merge branch 'develop' into three-eyed-raven
nikkothari22 Aug 29, 2024
1cdee6b
Merge branch 'develop' into three-eyed-raven
nikkothari22 Sep 2, 2024
07f920b
chore: linting
nikkothari22 Sep 2, 2024
8a17760
chore: semgrep
nikkothari22 Sep 2, 2024
7c2225d
fix: do not trigger AI for polls
nikkothari22 Sep 2, 2024
5a9e1fa
chore: deps
nikkothari22 Sep 4, 2024
0f37cdf
Merge branch 'develop' into three-eyed-raven
nikkothari22 Sep 7, 2024
9383e66
Merge branch 'develop' into three-eyed-raven
nikkothari22 Sep 8, 2024
2d9f90d
feat: handle file uploads for AI bot
nikkothari22 Sep 11, 2024
714441e
feat: sync bots with OpenAI assistants
nikkothari22 Sep 11, 2024
af740d8
feat: OpenAI settings page in Raven
nikkothari22 Sep 13, 2024
7f3aa0c
feat: forms for bots, commands and prompts
nikkothari22 Sep 14, 2024
d2a1117
wip: function builder
nikkothari22 Sep 14, 2024
cc79322
fix: allow table to scroll
nikkothari22 Sep 15, 2024
c90b543
fix: error handling for AI functions
nikkothari22 Sep 17, 2024
121c999
fix: remove Raven from navbar items during install
nikkothari22 Sep 17, 2024
b6a718f
chore(deps): bump rollup from 2.79.1 to 2.79.2
dependabot[bot] Sep 27, 2024
a4de82b
Merge branch 'develop' into three-eyed-raven
nikkothari22 Sep 27, 2024
b61788a
feat: show API thinking spinner
nikkothari22 Sep 27, 2024
a437bf0
feat: ability to delete thread for channel admin
janhvipatil Sep 27, 2024
681ba42
feat: support for delete and get docs
nikkothari22 Sep 27, 2024
15cb7b1
fix: order lists by modified
nikkothari22 Sep 27, 2024
a162c3d
feat: permission check for all functions
nikkothari22 Sep 27, 2024
b33f05a
fix: translate all errors thrown
nikkothari22 Sep 27, 2024
97e611b
fix: wrap error in translation
nikkothari22 Sep 27, 2024
4a49afd
fix: do not send notifications for hiding link previews
nikkothari22 Sep 28, 2024
915fbdb
feat: use fresh cache if older than a week
nikkothari22 Sep 28, 2024
56d4959
feat: allow users to preview dynamic instructions
nikkothari22 Sep 28, 2024
f379681
fix: Link field bug
nikkothari22 Sep 28, 2024
a544a3d
chore: mention standard Jinja variables are available
nikkothari22 Sep 28, 2024
9cbdf58
fix: Link field value
nikkothari22 Sep 28, 2024
2c31323
fix: cursor on image chevron
nikkothari22 Sep 28, 2024
560724f
feat: show dirty state for forms
nikkothari22 Sep 28, 2024
051ad53
feat: add functions to bots from Raven
nikkothari22 Sep 28, 2024
e6732c4
feat: add print and workflow actions in DocType link renderer
nikkothari22 Sep 29, 2024
e5fc60c
fix: do not revalidate workflow transitions
nikkothari22 Sep 29, 2024
62253ce
feat: set default vlaues when creating docs
nikkothari22 Sep 29, 2024
bebb987
fix: file preview UI
nikkothari22 Sep 29, 2024
37e0e00
fix: props on FileMessage
nikkothari22 Sep 29, 2024
66cdee7
feat: bulk create and update functions by Bots
nikkothari22 Sep 29, 2024
4828950
feat: group functions by type in dropdown
nikkothari22 Sep 29, 2024
ef7fe06
fix: added check to only update bots with AI enabled when fx is updated
nikkothari22 Sep 29, 2024
c0cc36d
fix: app logo in sidebar + raven chat placement in v16
nikkothari22 Sep 30, 2024
71bf9b8
feat: show AI not enabled callout in all pages
nikkothari22 Sep 30, 2024
02a4456
feat: show regular threads on Threads page
nikkothari22 Sep 30, 2024
01b12aa
fix: alignment of threads and saved message links
nikkothari22 Sep 30, 2024
c955f79
fix: allow users to use child table fields in document functions
nikkothari22 Sep 30, 2024
70cf7fa
feat: allow users to select code interpreter for bots
nikkothari22 Sep 30, 2024
3bda6f3
feat: doctype variable builder
nikkothari22 Oct 1, 2024
9662ecc
fix: form validations and mutations
nikkothari22 Oct 1, 2024
c27223f
refactor: function form
nikkothari22 Oct 1, 2024
fa450af
feat: show open chat button on bot
nikkothari22 Oct 1, 2024
159c3e0
feat: custom function variable builder
nikkothari22 Oct 1, 2024
cf9699e
feat: bring required child tables in the doctype field import
nikkothari22 Oct 1, 2024
6b90460
fix: file drop height and width for thread drawer
nikkothari22 Oct 1, 2024
a54af31
fix: remove max length
nikkothari22 Oct 1, 2024
26dd074
fix: file drop zone for new threads
nikkothari22 Oct 1, 2024
2f8af2e
Apply suggestions from code review
nikkothari22 Oct 1, 2024
34d0a50
Merge pull request #1069 from The-Commit-Company/ability-to-delete-th…
nikkothari22 Oct 1, 2024
2492bf7
Merge branch 'develop' into three-eyed-raven
nikkothari22 Oct 1, 2024
5b3bac6
fix: animations and layout
nikkothari22 Oct 1, 2024
4ddda81
fix: styling of editor
nikkothari22 Oct 1, 2024
5331bae
feat: saved prompts feature
nikkothari22 Oct 1, 2024
3ef334e
chore: linter
nikkothari22 Oct 1, 2024
7875a42
feat: support for excel files and updating docs
nikkothari22 Oct 2, 2024
3f749b2
fix: ignore frontend for semgrep
nikkothari22 Oct 2, 2024
dd8cc19
chore: ignore React app for semgrep
nikkothari22 Oct 2, 2024
0cd3f41
Merge pull request #1068 from The-Commit-Company/dependabot/npm_and_y…
nikkothari22 Oct 2, 2024
5666d58
Merge branch 'develop' into three-eyed-raven
nikkothari22 Oct 2, 2024
0427cc2
fix: bulk function calls and parsing
nikkothari22 Oct 2, 2024
dfec548
fix: support for strict functions
nikkothari22 Oct 2, 2024
8ea706a
Merge pull request #1035 from The-Commit-Company/three-eyed-raven
nikkothari22 Oct 2, 2024
9d48bfe
fix: AI event dark mode bg color
nikkothari22 Oct 2, 2024
400ce14
fix: allow autocomplete in valid field types
nikkothari22 Oct 2, 2024
8cb5f2c
feat: add debug mode
nikkothari22 Oct 2, 2024
a5cf534
fix: show updated docs
nikkothari22 Oct 2, 2024
a5511d0
Merge pull request #1072 from The-Commit-Company/three-eyed-raven
nikkothari22 Oct 2, 2024
12cd920
fix: readme installation step
nikkothari22 Oct 3, 2024
b6c1a00
feat: translation on sidebar
nikkothari22 Oct 6, 2024
381b273
feat: translate settings pages
nikkothari22 Oct 6, 2024
88d2263
Merge pull request #1073 from The-Commit-Company/translations
nikkothari22 Oct 6, 2024
3f35692
feat: support details tag
nikkothari22 Oct 9, 2024
4409019
chore: added debug mode checkbox in Bot form
nikkothari22 Oct 9, 2024
414e1e9
fix: allow users to view functions from bots
nikkothari22 Oct 9, 2024
428f64a
feat: attach files to document function
nikkothari22 Oct 9, 2024
ad368ae
Merge pull request #1074 from The-Commit-Company:finish-ai-linking-fi…
nikkothari22 Oct 9, 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
3 changes: 2 additions & 1 deletion .semgrepignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
.devcontainer/docker-compose.yml
.devcontainer/docker-compose.yml
frontend/
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,11 @@ Since Raven is a Frappe app, it can be installed via [frappe-bench](https://frap
Once you have [setup your bench](https://frappeframework.com/docs/v14/user/en/installation) and your [site](https://frappeframework.com/docs/v14/user/en/tutorial/install-and-setup-bench), you can install the app via the following commands:

```bash
bench get-app https://github.com/The-Commit-Company/Raven.git
bench --site yoursite.name install-app raven
bench get-app https://github.com/The-Commit-Company/raven.git
```

```bash
bench --site <yoursite.name> install-app raven
```

Post this, you can access Raven on your Frappe site at the `/raven` endpoint (e.g. https://yoursite.com/raven).
Expand Down
3 changes: 2 additions & 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.7.1",
"version": "2.0.0",
"type": "module",
"scripts": {
"dev": "vite",
Expand Down Expand Up @@ -47,6 +47,7 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-dropzone": "^14.2.3",
"react-error-boundary": "^4.0.13",
"react-hook-form": "^7.52.2",
"react-icons": "^5.3.0",
"react-idle-timer": "^5.7.2",
Expand Down
89 changes: 81 additions & 8 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,15 @@ import { ThemeProvider } from './ThemeProvider'
import { Toaster } from 'sonner'
import { useStickyState } from './hooks/useStickyState'
import MobileTabsPage from './pages/MobileTabsPage'
import { UserProfile } from './components/feature/userSettings/UserProfile/UserProfile'
import Cookies from 'js-cookie'

/** Following keys will not be cached in app cache */
const NO_CACHE_KEYS = [
"frappe.desk.form.load.getdoctype",
"frappe.desk.search.search_link",
"frappe.model.workflow.get_transitions",
"frappe.desk.reportview.get_count"
]


const router = createBrowserRouter(
Expand All @@ -28,11 +36,36 @@ const router = createBrowserRouter(
</Route>
<Route path="saved-messages" lazy={() => import('./components/feature/saved-messages/SavedMessages')} />
<Route path="settings" lazy={() => import('./pages/settings/Settings')}>
<Route index element={<UserProfile />} />
<Route path="profile" element={<UserProfile />} />
<Route index lazy={() => import('./components/feature/userSettings/UserProfile/UserProfile')} />
<Route path="profile" lazy={() => import('./components/feature/userSettings/UserProfile/UserProfile')} />
<Route path="users" lazy={() => import('./components/feature/userSettings/Users/AddUsers')} />
<Route path="frappe-hr" lazy={() => import('./pages/settings/Integrations/FrappeHR')} />
{/* <Route path="bots" lazy={() => import('./components/feature/userSettings/Bots')} /> */}
<Route path="hr" lazy={() => import('./pages/settings/Integrations/FrappeHR')} />
<Route path="bots" >
<Route index lazy={() => import('./pages/settings/AI/BotList')} />
<Route path="create" lazy={() => import('./pages/settings/AI/CreateBot')} />
<Route path=":ID" lazy={() => import('./pages/settings/AI/ViewBot')} />
</Route>

<Route path="functions">
<Route index lazy={() => import('./pages/settings/AI/FunctionList')} />
<Route path="create" lazy={() => import('./pages/settings/AI/CreateFunction')} />
<Route path=":ID" lazy={() => import('./pages/settings/AI/ViewFunction')} />
</Route>


<Route path="instructions">
<Route index lazy={() => import('./pages/settings/AI/InstructionTemplateList')} />
<Route path="create" lazy={() => import('./pages/settings/AI/CreateInstructionTemplate')} />
<Route path=":ID" lazy={() => import('./pages/settings/AI/ViewInstructionTemplate')} />
</Route>

<Route path="commands">
<Route index lazy={() => import('./pages/settings/AI/SavedPromptsList')} />
<Route path="create" lazy={() => import('./pages/settings/AI/CreateSavedPrompt')} />
<Route path=":ID" lazy={() => import('./pages/settings/AI/ViewSavedPrompt')} />
</Route>

<Route path="openai-settings" lazy={() => import('./pages/settings/AI/OpenAISettings')} />
</Route>
<Route path=":channelID" lazy={() => import('@/pages/ChatSpace')}>
<Route path="thread/:threadID" lazy={() => import('./components/feature/threads/ThreadDrawer/ThreadDrawer')} />
Expand Down Expand Up @@ -102,12 +135,52 @@ function App() {

function localStorageProvider() {
// When initializing, we restore the data from `localStorage` into a map.
const map = new Map<string, any>(JSON.parse(localStorage.getItem('app-cache') || '[]'))
// Check if local storage is recent (less than a week). Else start with a fresh cache.
const timestamp = localStorage.getItem('app-cache-timestamp')
let cache = '[]'
if (timestamp && Date.now() - parseInt(timestamp) < 7 * 24 * 60 * 60 * 1000) {
const localCache = localStorage.getItem('app-cache')
if (localCache) {
cache = localCache
}
}
const map = new Map<string, any>(JSON.parse(cache))

// Before unloading the app, we write back all the data into `localStorage`.
window.addEventListener('beforeunload', () => {
const appCache = JSON.stringify(Array.from(map.entries()))
localStorage.setItem('app-cache', appCache)


// Check if the user is logged in
const user_id = Cookies.get('user_id')
if (!user_id || user_id === 'Guest') {
localStorage.removeItem('app-cache')
localStorage.removeItem('app-cache-timestamp')
} else {
const entries = map.entries()

const cacheEntries = []

for (const [key, value] of entries) {

let hasCacheKey = false
for (const cacheKey of NO_CACHE_KEYS) {
if (key.includes(cacheKey)) {
hasCacheKey = true
break
}
}

//Do not cache doctype meta and search link
if (hasCacheKey) {
continue
}
cacheEntries.push([key, value])
}
const appCache = JSON.stringify(cacheEntries)
localStorage.setItem('app-cache', appCache)
localStorage.setItem('app-cache-timestamp', Date.now().toString())
}

})

// We still use the map for write & read for performance.
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/common/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ export const Label = ({ children, isRequired, ...props }: LabelProps) => {

export const HelperText = (props: TextProps) => {
return (
<Text as='span' size='1' color='gray' {...props} />
<Text as='span' size='2' color='gray' {...props} />
)
}

export const ErrorText = (props: TextProps) => {
return (
<Text as='p' size='1' color='red' {...props} />
<Text as='p' size='2' color='red' {...props} />
)
}
9 changes: 5 additions & 4 deletions frontend/src/components/common/LinkField/LinkField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export interface LinkFieldProps {

const LinkField = ({ doctype, filters, label, placeholder, value, required, setValue, disabled, autofocus, dropdownClass }: LinkFieldProps) => {

const [searchText, setSearchText] = useState('')
const [searchText, setSearchText] = useState(value ?? '')

const isDesktop = useIsDesktop()

Expand All @@ -49,14 +49,15 @@ const LinkField = ({ doctype, filters, label, placeholder, value, required, setV
itemToString(item) {
return item ? item.value : ''
},
selectedItem: items.find(item => item.value === value),
onSelectedItemChange({ selectedItem }) {

setValue(selectedItem?.value ?? '')
},
defaultInputValue: value,
defaultIsOpen: isDesktop && autofocus,
defaultSelectedItem: items.find(item => item.value === value),
})

console.log(isOpen)

return <div className="w-full">
<div className="flex flex-col">
<Label className="w-fit" isRequired={required} {...getLabelProps()}>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/common/LinkField/LinkFormField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import LinkField, { LinkFieldProps } from './LinkField'

interface LinkFormFieldProps extends Omit<LinkFieldProps, 'value' | 'setValue'> {
name: string,
rules: ControllerProps['rules'],
rules?: ControllerProps['rules'],
disabled?: boolean
}

Expand Down
12 changes: 10 additions & 2 deletions frontend/src/components/feature/CommandMenu/CommandMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { DIALOG_CONTENT_CLASS } from '@/utils/layout/dialog'
import { Dialog } from '@radix-ui/themes'
import { Dialog, VisuallyHidden } from '@radix-ui/themes'
import { Command } from 'cmdk'
import { useEffect } from 'react'
import './commandMenu.styles.css'
Expand All @@ -11,6 +11,7 @@ import ArchivedChannelList from './ArchivedChannelList'
import { atom, useAtom } from 'jotai'
import { useIsDesktop } from '@/hooks/useMediaQuery'
import { Drawer, DrawerContent } from '@/components/layout/Drawer'
import SettingsList from './SettingsList'

export const commandMenuOpenAtom = atom(false)

Expand All @@ -21,7 +22,7 @@ const CommandMenu = () => {
useEffect(() => {

const down = (e: KeyboardEvent) => {
if (e.key === 'k' && (e.metaKey || e.ctrlKey)) {
if (e.key === 'k' && (e.metaKey || e.ctrlKey) && !e.shiftKey) {
e.preventDefault()
setOpen((open) => !open)
}
Expand All @@ -37,6 +38,12 @@ const CommandMenu = () => {
return (
<Dialog.Root open={open} onOpenChange={setOpen}>
<Dialog.Content className={clsx(DIALOG_CONTENT_CLASS, 'p-4 rounded-md')}>
<VisuallyHidden>
<Dialog.Title>Command Menu</Dialog.Title>
<Dialog.Description>
Search or type a command
</Dialog.Description>
</VisuallyHidden>
<CommandList />
</Dialog.Content>
</Dialog.Root>
Expand Down Expand Up @@ -69,6 +76,7 @@ export const CommandList = () => {
<Command.Empty>No results found.</Command.Empty>
<ChannelList />
<UserList />
<SettingsList />

{/* TODO: Make these commands work */}
{/* <Command.Group heading="Commands">
Expand Down
77 changes: 77 additions & 0 deletions frontend/src/components/feature/CommandMenu/SettingsList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { Command } from 'cmdk'
import { useSetAtom } from 'jotai'
import { BiBot, BiFile, BiGroup, BiMessageSquareDots, BiUserCircle } from 'react-icons/bi'
import { useNavigate } from 'react-router-dom'
import { commandMenuOpenAtom } from './CommandMenu'
import { PiOpenAiLogo } from 'react-icons/pi'
import { LuFunctionSquare } from 'react-icons/lu'

type Props = {}

const ICON_SIZE = 16

const SettingsList = (props: Props) => {

const navigate = useNavigate()

const setOpen = useSetAtom(commandMenuOpenAtom)

const onSelect = (value: string) => {
navigate(`/channel/settings/${value}`)
setOpen(false)
}
return (
<Command.Group heading='Settings'>
<Command.Item value='profile' onSelect={onSelect}>
<BiUserCircle size={ICON_SIZE} />
Profile
</Command.Item>
<Command.Item value='users' onSelect={onSelect}>
<BiGroup size={ICON_SIZE} />
Users
</Command.Item>
<Command.Item value='hr' onSelect={onSelect}>
<svg fill="none" viewBox="0 0 32 32" width={18} height={18} xmlns="http://www.w3.org/2000/svg">
<g clipPath="url(#clip0_2850_17380)">
<path d="M25.5561 0H6.44394C2.88505 0 0 2.88505 0 6.44394V25.5561C0 29.115 2.88505 32 6.44394 32H25.5561C29.115 32 32 29.115 32 25.5561V6.44394C32 2.88505 29.115 0 25.5561 0Z" fill="#A1EEC9"></path>
<path d="M15.4061 18.5995C12.4184 18.5995 9.97265 16.1684 9.97265 13.1661V12.6974L12.8724 12.7267L12.8431 13.1661C12.8431 14.572 13.9855 15.729 15.4061 15.729H16.5777C17.9836 15.729 19.1406 14.5867 19.1406 13.1661V11.9944C19.1406 10.5885 17.9983 9.43151 16.5777 9.43151H9.94336L9.97265 6.53174L16.5777 6.56103C19.5653 6.56103 22.0111 8.99215 22.0111 11.9944V13.1661C22.0111 16.1537 19.58 18.5995 16.5777 18.5995H15.4061Z" fill="#0B313A"></path>
<path d="M8.78613 23.2714C10.7779 21.5286 13.3408 20.5474 16.0063 20.5474C18.6717 20.5474 21.2346 21.5286 23.2264 23.3153L21.2932 25.4389C19.8287 24.1355 17.9541 23.4178 16.0063 23.4178C14.0584 23.4178 12.1692 24.1355 10.7047 25.4535L8.80078 23.2714H8.78613Z" fill="#0B313A"></path>
</g>
<defs>
<clipPath id="clip0_2850_17380">
<rect fill="white" height="32" width="32"></rect>
</clipPath>
</defs>
</svg>
HR
</Command.Item>

<Command.Item value='bots' onSelect={onSelect}>
<BiBot size={ICON_SIZE} />
Bots
</Command.Item>

<Command.Item value='functions' onSelect={onSelect}>
<LuFunctionSquare size={ICON_SIZE} />
Functions
</Command.Item>

<Command.Item value='instructions' onSelect={onSelect}>
<BiFile size={ICON_SIZE} />
Instructions
</Command.Item>

<Command.Item value='commands' onSelect={onSelect}>
<BiMessageSquareDots size={ICON_SIZE} />
Commands
</Command.Item>

<Command.Item value='openai-settings' onSelect={onSelect}>
<PiOpenAiLogo size={ICON_SIZE} />
OpenAI Settings
</Command.Item>
</Command.Group>
)
}

export default SettingsList
49 changes: 49 additions & 0 deletions frontend/src/components/feature/ai/AIEvent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { Loader } from '@/components/common/Loader'
import { Text } from '@radix-ui/themes'
import clsx from 'clsx'
import { useFrappeEventListener } from 'frappe-react-sdk'
import { useEffect, useState } from 'react'

type Props = {
channelID: string
}

const AIEvent = ({ channelID }: Props) => {
const [aiEvent, setAIEvent] = useState("")
const [showAIEvent, setShowAIEvent] = useState(false)

useFrappeEventListener("ai_event", (data) => {
if (data.channel_id === channelID) {
setAIEvent(data.text)
setShowAIEvent(true)
}
})

useFrappeEventListener("ai_event_clear", (data) => {
if (data.channel_id === channelID) {
setAIEvent("")
}
})

useEffect(() => {
if (!aiEvent) {
setTimeout(() => {
setShowAIEvent(false)
}, 300)
}
}, [aiEvent])

return (
<div className={clsx(
'w-full transition-all duration-300 ease-ease-out-quart',
showAIEvent ? 'translate-y-0 opacity-100 z-50' : 'translate-y-full opacity-0 h-0'
)}>
<div className="flex items-center gap-2 py-2 px-2 bg-white dark:bg-gray-2">
<Loader />
<Text size='2'>{aiEvent}</Text>
</div>
</div>
)
}

export default AIEvent
Loading
Loading