feat: add message and modal api to window object
This commit is contained in:
parent
a2ec18d9be
commit
f8d9b437c2
@ -1,5 +1,6 @@
|
||||
import { message, Modal } from 'antd'
|
||||
import { findIndex, pullAt } from 'lodash'
|
||||
import React, { useState } from 'react'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
|
||||
let id = 0
|
||||
let onPop = () => {}
|
||||
@ -17,6 +18,8 @@ type ElementItem = {
|
||||
|
||||
const TopViewContainer: React.FC<Props> = ({ children }) => {
|
||||
const [elements, setElements] = useState<ElementItem[]>([])
|
||||
const [messageApi, messageContextHolder] = message.useMessage()
|
||||
const [modal, modalContextHolder] = Modal.useModal()
|
||||
|
||||
onPop = () => {
|
||||
const views = [...elements]
|
||||
@ -34,9 +37,16 @@ const TopViewContainer: React.FC<Props> = ({ children }) => {
|
||||
setElements(views)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
window.message = messageApi
|
||||
window.modal = modal
|
||||
}, [messageApi, modal])
|
||||
|
||||
return (
|
||||
<>
|
||||
{children}
|
||||
{messageContextHolder}
|
||||
{modalContextHolder}
|
||||
{elements.length > 0 && (
|
||||
<div style={{ display: 'flex', flex: 1, position: 'absolute', width: '100%', height: '100%' }}>
|
||||
<div style={{ position: 'absolute', width: '100%', height: '100%' }} onClick={onPop} />
|
||||
|
||||
10
src/renderer/src/env.d.ts
vendored
10
src/renderer/src/env.d.ts
vendored
@ -1 +1,11 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
import { MessageInstance } from 'antd/es/message/interface'
|
||||
import { HookAPI } from 'antd/es/modal/useModal'
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
message: MessageInstance
|
||||
modal: HookAPI
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar'
|
||||
import { SYSTEM_ASSISTANTS } from '@renderer/config/assistant'
|
||||
import { Button, Col, message, Row, Tooltip, Typography } from 'antd'
|
||||
import { Button, Col, Row, Tooltip, Typography } from 'antd'
|
||||
import { find, groupBy } from 'lodash'
|
||||
import { FC } from 'react'
|
||||
import styled from 'styled-components'
|
||||
@ -14,26 +14,21 @@ const { Title } = Typography
|
||||
const AppsPage: FC = () => {
|
||||
const { assistants, addAssistant } = useAssistants()
|
||||
const assistantGroups = groupBy(SYSTEM_ASSISTANTS, 'group')
|
||||
const [messageApi, contextHolder] = message.useMessage()
|
||||
|
||||
const onAddAssistant = (assistant: SystemAssistant) => {
|
||||
addAssistant({
|
||||
...getDefaultAssistant(),
|
||||
...assistant
|
||||
})
|
||||
messageApi.destroy()
|
||||
messageApi.open({
|
||||
type: 'success',
|
||||
window.message.success({
|
||||
content: 'Assistant added successfully',
|
||||
style: {
|
||||
marginTop: '5vh'
|
||||
}
|
||||
key: 'assistant-added',
|
||||
style: { marginTop: '5vh' }
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<Container>
|
||||
{contextHolder}
|
||||
<Navbar>
|
||||
<NavbarCenter>Assistant Market</NavbarCenter>
|
||||
</Navbar>
|
||||
|
||||
@ -5,14 +5,44 @@ import { FC } from 'react'
|
||||
import styled from 'styled-components'
|
||||
import Logo from '@renderer/assets/images/logo.png'
|
||||
import useAvatar from '@renderer/hooks/useAvatar'
|
||||
import { CopyOutlined, DeleteOutlined } from '@ant-design/icons'
|
||||
|
||||
const MessageItem: FC<{ message: Message }> = ({ message }) => {
|
||||
interface Props {
|
||||
message: Message
|
||||
showMenu?: boolean
|
||||
onDeleteMessage?: (message: Message) => void
|
||||
}
|
||||
|
||||
const MessageItem: FC<Props> = ({ message, showMenu, onDeleteMessage }) => {
|
||||
const avatar = useAvatar()
|
||||
|
||||
const onCopy = () => {
|
||||
navigator.clipboard.writeText(message.content)
|
||||
window.message.success({ content: 'Copied!', key: 'copy-message' })
|
||||
}
|
||||
|
||||
const onDelete = async () => {
|
||||
const confirmed = await window.modal.confirm({
|
||||
title: 'Delete Message',
|
||||
content: 'Are you sure you want to delete this message?',
|
||||
okText: 'Delete',
|
||||
okType: 'danger'
|
||||
})
|
||||
confirmed && onDeleteMessage?.(message)
|
||||
}
|
||||
|
||||
return (
|
||||
<MessageContainer key={message.id}>
|
||||
<AvatarWrapper>{message.role === 'assistant' ? <Avatar src={Logo} /> : <Avatar src={avatar} />}</AvatarWrapper>
|
||||
<MessageContent>
|
||||
<div className="markdown" dangerouslySetInnerHTML={{ __html: marked(message.content) }} />
|
||||
{showMenu && (
|
||||
<MenusBar className="menubar">
|
||||
<CopyOutlined onClick={onCopy} />
|
||||
<DeleteOutlined onClick={onDelete} />
|
||||
</MenusBar>
|
||||
)}
|
||||
</MessageContent>
|
||||
</MessageContainer>
|
||||
)
|
||||
}
|
||||
@ -28,4 +58,34 @@ const AvatarWrapper = styled.div`
|
||||
margin-right: 10px;
|
||||
`
|
||||
|
||||
const MessageContent = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
.menubar {
|
||||
opacity: 0;
|
||||
}
|
||||
&:hover {
|
||||
.menubar {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const MenusBar = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
gap: 6px;
|
||||
.anticon {
|
||||
cursor: pointer;
|
||||
margin-right: 8px;
|
||||
font-size: 15px;
|
||||
color: var(--color-icon);
|
||||
&:hover {
|
||||
color: var(--color-text-1);
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export default MessageItem
|
||||
|
||||
@ -52,12 +52,21 @@ const Messages: FC<Props> = ({ assistant, topic }) => {
|
||||
}
|
||||
}, [assistant, messages, topic, updateTopic])
|
||||
|
||||
const onDeleteMessage = (message: Message) => {
|
||||
const _messages = messages.filter((m) => m.id !== message.id)
|
||||
setMessages(_messages)
|
||||
localforage.setItem(`topic:${topic.id}`, {
|
||||
...topic,
|
||||
messages: _messages
|
||||
})
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const unsubscribes = [
|
||||
EventEmitter.on(EVENT_NAMES.SEND_MESSAGE, async (msg: Message) => {
|
||||
console.debug({ assistant, provider, message: msg, topic })
|
||||
onSendMessage(msg)
|
||||
fetchChatCompletion({ assistant, messages: [messages, msg], topic, onResponse: setLastMessage })
|
||||
fetchChatCompletion({ assistant, messages: [...messages, msg], topic, onResponse: setLastMessage })
|
||||
}),
|
||||
EventEmitter.on(EVENT_NAMES.AI_CHAT_COMPLETION, async (msg: Message) => {
|
||||
setLastMessage(null)
|
||||
@ -84,10 +93,10 @@ const Messages: FC<Props> = ({ assistant, topic }) => {
|
||||
useEffect(() => hljs.highlightAll())
|
||||
|
||||
return (
|
||||
<Container id="topics">
|
||||
<Container id="messages">
|
||||
{lastMessage && <MessageItem message={lastMessage} />}
|
||||
{reverse([...messages]).map((message) => (
|
||||
<MessageItem message={message} key={message.id} />
|
||||
<MessageItem message={message} key={message.id} showMenu onDeleteMessage={onDeleteMessage} />
|
||||
))}
|
||||
<MessageItem message={assistantDefaultMessage} />
|
||||
</Container>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user