feat: init new plugin system (#3323)

This commit is contained in:
Alex Yang
2023-07-20 18:52:29 +08:00
committed by GitHub
parent 604b53d9a4
commit 19055baa49
45 changed files with 768 additions and 389 deletions

View File

@@ -1,11 +1,9 @@
import { IconButton } from '@affine/component';
import { SendIcon } from '@blocksuite/icons';
import { rootStore } from '@toeverything/plugin-infra/manager';
import type { PluginUIAdapter } from '@toeverything/plugin-infra/type';
import { Provider, useAtomValue, useSetAtom } from 'jotai';
import { contentLayoutAtom } from '@toeverything/plugin-infra/manager';
import { useAtomValue, useSetAtom } from 'jotai';
import type { ReactElement } from 'react';
import { StrictMode, Suspense, useCallback, useState } from 'react';
import { createRoot } from 'react-dom/client';
import { Suspense, useCallback, useState } from 'react';
import { ConversationList } from '../core/components/conversation-list';
import { FollowingUp } from '../core/components/following-up';
@@ -17,51 +15,6 @@ import {
textareaStyle,
} from './index.css';
if (typeof window === 'undefined') {
import('@blocksuite/blocks')
.then(({ FormatQuickBar }) => {
FormatQuickBar.customElements.push((_page, getSelection) => {
const div = document.createElement('div');
const root = createRoot(div);
const AskAI = (): ReactElement => {
const { conversationAtom } = useChatAtoms();
const call = useSetAtom(conversationAtom);
const onClickAskAI = useCallback(() => {
const selection = getSelection();
if (selection != null) {
const text = selection.models
.map(model => {
return model.text?.toString();
})
.filter((v): v is string => Boolean(v))
.join('\n');
console.log('selected text:', text);
call(
`I selected some text from the document: \n"${text}."`
).catch(err => {
console.error(err);
});
}
}, [call]);
return <div onClick={onClickAskAI}>Ask AI</div>;
};
root.render(
<StrictMode>
<Provider store={rootStore}>
<AskAI />
</Provider>
</StrictMode>
);
return div;
});
})
.catch(error => {
console.error(error);
});
}
const Actions = () => {
const { conversationAtom, followingUpAtoms } = useChatAtoms();
const call = useSetAtom(conversationAtom);
@@ -108,12 +61,10 @@ const DetailContentImpl = () => {
);
};
export const DetailContent: PluginUIAdapter['detailContent'] = ({
contentLayoutAtom,
}): ReactElement => {
export const DetailContent = (): ReactElement => {
const layout = useAtomValue(contentLayoutAtom);
const key = useAtomValue(openAIApiKeyAtom);
if (layout === 'editor' || layout.second !== 'com.affine.copilot') {
if (layout === 'editor' || layout.second !== 'copilot') {
return <></>;
}
if (!key) {

View File

@@ -1,12 +1,10 @@
import { IconButton, Tooltip } from '@affine/component';
import type { PluginUIAdapter } from '@toeverything/plugin-infra/type';
import { contentLayoutAtom } from '@toeverything/plugin-infra/manager';
import { useSetAtom } from 'jotai';
import type { ReactElement } from 'react';
import { useCallback } from 'react';
export const HeaderItem: PluginUIAdapter['headerItem'] = ({
contentLayoutAtom,
}): ReactElement => {
export const HeaderItem = (): ReactElement => {
const setLayout = useSetAtom(contentLayoutAtom);
return (
<Tooltip content="Chat with AI" placement="bottom-end">
@@ -18,7 +16,7 @@ export const HeaderItem: PluginUIAdapter['headerItem'] = ({
return {
direction: 'horizontal',
first: 'editor',
second: 'com.affine.copilot',
second: 'copilot',
splitPercentage: 70,
};
} else {

View File

@@ -1,5 +1,4 @@
import { Button } from '@affine/component';
import { WorkspaceAvatar } from '@affine/component/workspace-avatar';
import { PlusIcon, ResetIcon } from '@blocksuite/icons';
import { clsx } from 'clsx';
import type { MessageType } from 'langchain/schema';
@@ -31,7 +30,6 @@ export const Conversation = (props: ConversationProps): ReactElement => {
[styles.avatarRightStyle]: props.type === 'human',
})}
>
<WorkspaceAvatar workspace={null} />
<div className={styles.conversationContainerStyle}>
<div
className={clsx(styles.conversationStyle, {

View File

@@ -1,7 +1,6 @@
import type { IndexedDBChatMessageHistory } from '@affine/copilot/core/langchain/message-history';
import { atom, useAtomValue } from 'jotai';
import { atomWithDefault } from 'jotai/utils';
import { atomWithStorage } from 'jotai/utils';
import { atomWithDefault, atomWithStorage } from 'jotai/utils';
import type { WritableAtom } from 'jotai/vanilla';
import type { LLMChain } from 'langchain/chains';
import { type ConversationChain } from 'langchain/chains';

View File

@@ -1,31 +1,33 @@
import { definePlugin } from '@toeverything/plugin-infra/manager';
import { ReleaseStage } from '@toeverything/plugin-infra/type';
import type { PluginContext } from '@toeverything/plugin-infra/entry';
import { createElement } from 'react';
import { createRoot } from 'react-dom/client';
definePlugin(
{
id: 'com.affine.copilot',
name: {
fallback: 'AFFiNE Copilot',
i18nKey: 'com.affine.copilot.name',
},
description: {
fallback:
'AFFiNE Copilot will help you with best writing experience on the World.',
},
publisher: {
name: {
fallback: 'AFFiNE',
},
link: 'https://affine.pro',
},
stage: ReleaseStage.NIGHTLY,
version: '0.0.1',
commands: [],
},
{
load: () => import('./UI/index'),
hotModuleReload: onHot =>
import.meta.webpackHot &&
import.meta.webpackHot.accept('./UI', () => onHot(import('./UI/index'))),
}
);
import { DetailContent } from './UI/detail-content';
import { HeaderItem } from './UI/header-item';
export const entry = (context: PluginContext) => {
context.register('headerItem', div => {
const root = createRoot(div);
root.render(
createElement(context.utils.PluginProvider, {}, createElement(HeaderItem))
);
return () => {
root.unmount();
};
});
context.register('window', div => {
const root = createRoot(div);
root.render(
createElement(
context.utils.PluginProvider,
{},
createElement(DetailContent)
)
);
return () => {
root.unmount();
};
});
return () => {};
};