feat: 暂存,添加app-manager

This commit is contained in:
xion 2024-10-04 23:06:56 +08:00
parent 969243cbbb
commit 272ceaa6a6
9 changed files with 227 additions and 2 deletions

View File

@ -20,6 +20,7 @@
"@kevisual/codemirror": "^0.0.2", "@kevisual/codemirror": "^0.0.2",
"@kevisual/query": "^0.0.6", "@kevisual/query": "^0.0.6",
"@kevisual/ui": "^0.0.2", "@kevisual/ui": "^0.0.2",
"@monaco-editor/react": "^4.6.0",
"@uiw/react-textarea-code-editor": "^3.0.2", "@uiw/react-textarea-code-editor": "^3.0.2",
"@xyflow/react": "^12.3.1", "@xyflow/react": "^12.3.1",
"antd": "^5.21.1", "antd": "^5.21.1",
@ -34,6 +35,7 @@
"nanoid": "^5.0.7", "nanoid": "^5.0.7",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"react-resizable-panels": "^2.1.4",
"react-router": "^6.26.2", "react-router": "^6.26.2",
"react-router-dom": "^6.26.2", "react-router-dom": "^6.26.2",
"react-toastify": "^10.0.5", "react-toastify": "^10.0.5",

51
pnpm-lock.yaml generated
View File

@ -32,6 +32,9 @@ importers:
'@kevisual/ui': '@kevisual/ui':
specifier: ^0.0.2 specifier: ^0.0.2
version: 0.0.2 version: 0.0.2
'@monaco-editor/react':
specifier: ^4.6.0
version: 4.6.0(monaco-editor@0.52.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@uiw/react-textarea-code-editor': '@uiw/react-textarea-code-editor':
specifier: ^3.0.2 specifier: ^3.0.2
version: 3.0.2(@babel/runtime@7.25.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) version: 3.0.2(@babel/runtime@7.25.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@ -74,6 +77,9 @@ importers:
react-dom: react-dom:
specifier: ^18.3.1 specifier: ^18.3.1
version: 18.3.1(react@18.3.1) version: 18.3.1(react@18.3.1)
react-resizable-panels:
specifier: ^2.1.4
version: 2.1.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
react-router: react-router:
specifier: ^6.26.2 specifier: ^6.26.2
version: 6.26.2(react@18.3.1) version: 6.26.2(react@18.3.1)
@ -577,6 +583,18 @@ packages:
'@kevisual/ui@0.0.2': '@kevisual/ui@0.0.2':
resolution: {integrity: sha512-MDZDQTrYToLyj3WhiVJQLJ0PUHiN4D0Z5yJIyGzzPewPGpP2xwNgKO1BFX37J95cGZckzCdZwTKP0XKAOq0QtA==} resolution: {integrity: sha512-MDZDQTrYToLyj3WhiVJQLJ0PUHiN4D0Z5yJIyGzzPewPGpP2xwNgKO1BFX37J95cGZckzCdZwTKP0XKAOq0QtA==}
'@monaco-editor/loader@1.4.0':
resolution: {integrity: sha512-00ioBig0x642hytVspPl7DbQyaSWRaolYie/UFNjoTdvoKPzo6xrXLhTk9ixgIKcLH5b5vDOjVNiGyY+uDCUlg==}
peerDependencies:
monaco-editor: '>= 0.21.0 < 1'
'@monaco-editor/react@4.6.0':
resolution: {integrity: sha512-RFkU9/i7cN2bsq/iTkurMWOEErmYcY6JiQI3Jn+WeR/FGISH8JbHERjpS9oRuSOPvDMJI0Z8nJeKkbOs9sBYQw==}
peerDependencies:
monaco-editor: '>= 0.25.0 < 1'
react: ^16.8.0 || ^17.0.0 || ^18.0.0
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
'@nodelib/fs.scandir@2.1.5': '@nodelib/fs.scandir@2.1.5':
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
@ -1773,6 +1791,9 @@ packages:
resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
engines: {node: '>=16 || 14 >=14.17'} engines: {node: '>=16 || 14 >=14.17'}
monaco-editor@0.52.0:
resolution: {integrity: sha512-OeWhNpABLCeTqubfqLMXGsqf6OmPU6pHM85kF3dhy6kq5hnhuVS1p3VrEW/XhWHc71P2tHyS5JFySD8mgs1crw==}
ms@2.1.3: ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
@ -2185,6 +2206,12 @@ packages:
resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
react-resizable-panels@2.1.4:
resolution: {integrity: sha512-kzue8lsoSBdyyd2IfXLQMMhNujOxRoGVus+63K95fQqleGxTfvgYLTzbwYMOODeAHqnkjb3WV/Ks7f5+gDYZuQ==}
peerDependencies:
react: ^16.14.0 || ^17.0.0 || ^18.0.0
react-dom: ^16.14.0 || ^17.0.0 || ^18.0.0
react-router-dom@6.26.2: react-router-dom@6.26.2:
resolution: {integrity: sha512-z7YkaEW0Dy35T3/QKPYB1LjMK2R1fxnHO8kWpUMTBdfVzZrWOiY9a7CtN8HqdWtDUWd5FY6Dl8HFsqVwH4uOtQ==} resolution: {integrity: sha512-z7YkaEW0Dy35T3/QKPYB1LjMK2R1fxnHO8kWpUMTBdfVzZrWOiY9a7CtN8HqdWtDUWd5FY6Dl8HFsqVwH4uOtQ==}
engines: {node: '>=14.0.0'} engines: {node: '>=14.0.0'}
@ -2312,6 +2339,9 @@ packages:
space-separated-tokens@2.0.2: space-separated-tokens@2.0.2:
resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==}
state-local@1.0.7:
resolution: {integrity: sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==}
string-convert@0.2.1: string-convert@0.2.1:
resolution: {integrity: sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==} resolution: {integrity: sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==}
@ -3037,6 +3067,18 @@ snapshots:
lodash-es: 4.17.21 lodash-es: 4.17.21
style-to-object: 1.0.8 style-to-object: 1.0.8
'@monaco-editor/loader@1.4.0(monaco-editor@0.52.0)':
dependencies:
monaco-editor: 0.52.0
state-local: 1.0.7
'@monaco-editor/react@4.6.0(monaco-editor@0.52.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
'@monaco-editor/loader': 1.4.0(monaco-editor@0.52.0)
monaco-editor: 0.52.0
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
'@nodelib/fs.scandir@2.1.5': '@nodelib/fs.scandir@2.1.5':
dependencies: dependencies:
'@nodelib/fs.stat': 2.0.5 '@nodelib/fs.stat': 2.0.5
@ -4373,6 +4415,8 @@ snapshots:
minipass@7.1.2: {} minipass@7.1.2: {}
monaco-editor@0.52.0: {}
ms@2.1.3: {} ms@2.1.3: {}
mz@2.7.0: mz@2.7.0:
@ -4853,6 +4897,11 @@ snapshots:
react-refresh@0.14.2: {} react-refresh@0.14.2: {}
react-resizable-panels@2.1.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
react-router-dom@6.26.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1): react-router-dom@6.26.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies: dependencies:
'@remix-run/router': 1.19.2 '@remix-run/router': 1.19.2
@ -5004,6 +5053,8 @@ snapshots:
space-separated-tokens@2.0.2: {} space-separated-tokens@2.0.2: {}
state-local@1.0.7: {}
string-convert@0.2.1: {} string-convert@0.2.1: {}
string-width@4.2.3: string-width@4.2.3:

View File

@ -2,7 +2,7 @@ import { useShallow } from 'zustand/react/shallow';
import { useAiStore } from './store/ai-store'; import { useAiStore } from './store/ai-store';
import { CloseOutlined, HistoryOutlined, PlusOutlined } from '@ant-design/icons'; import { CloseOutlined, HistoryOutlined, PlusOutlined } from '@ant-design/icons';
import { Button, Dropdown, Form, Input, message, Modal, Tooltip } from 'antd'; import { Button, Dropdown, Form, Input, message, Modal, Tooltip } from 'antd';
import { useEffect, useState } from 'react'; import { useEffect, useMemo, useState } from 'react';
import { TextArea } from '../container/components/TextArea'; import { TextArea } from '../container/components/TextArea';
import clsx from 'clsx'; import clsx from 'clsx';
import { query } from '@/modules'; import { query } from '@/modules';
@ -221,7 +221,11 @@ export const AiMoudle = () => {
const onSendNoPrompt = (value) => { const onSendNoPrompt = (value) => {
send({ type: 'messages', data: { message: value, root: true } }); send({ type: 'messages', data: { message: value, root: true } });
}; };
const inputs = useMemo(() => {
if (!aiStore.open) return [];
const inputs = form.getFieldValue('inputs'); const inputs = form.getFieldValue('inputs');
return inputs;
}, [aiStore.open]);
const isNotShow = inputs?.length === 0 || !inputs; const isNotShow = inputs?.length === 0 || !inputs;
const OnlyNormalMessage = ( const OnlyNormalMessage = (
<Tooltip title='不需要任何预设prompt'> <Tooltip title='不需要任何预设prompt'>

View File

@ -0,0 +1,26 @@
import Editor from '@monaco-editor/react';
import { useState } from 'react';
export const AppEditor = () => {
const [code, setCode] = useState('');
const [language, setLanguage] = useState('javascript');
return (
<div className='w-full h-full'>
<Editor
height={'100%'}
value={code}
language={language}
onChange={(value) => {
setCode(value || '');
}}
options={{
minimap: { enabled: false },
}}
defaultLanguage='javascript'
defaultValue='// some comment'
/>
</div>
);
};
export default AppEditor;

View File

@ -0,0 +1,36 @@
import { useParams } from 'react-router';
import { useAppStore } from './store';
import { lazy, useEffect } from 'react';
import { Left } from './panel/Left';
import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels';
import { EditorHeader } from './panel/EditorHeader';
// import AppEditor from './edit/Editor';
const AppEditor = lazy(() => import('./edit/Editor'));
export const App = () => {
const appStore = useAppStore();
const param = useParams();
const id = param.id as string;
useEffect(() => {
if (!id) return;
appStore.getData(id);
}, []);
if (!id) return <div>Not Found</div>;
return (
<div className='w-full h-full flex bg-slate-200'>
<PanelGroup autoSaveId='editor' direction='horizontal'>
<Panel defaultSize={25}>
<Left />
</Panel>
<PanelResizeHandle />
<Panel defaultSize={75}>
<div className='w-full h-full'>
<EditorHeader />
<AppEditor />
</div>
</Panel>
</PanelGroup>
</div>
);
};

View File

@ -0,0 +1,22 @@
import { useState } from 'react';
import { useAppStore } from '../store';
export const EditorHeader = () => {
const appStore = useAppStore();
const [headerList, setHeaderList] = useState([]);
return (
<div className=''>
<div className='px-2 border bg-[#f8f8f8]'>
<div className='flex justify-between items-center'>
<div className='flex items-center'>
<div className='text-lg font-semibold'>Header</div>
<div className='ml-2 text-xs text-gray-500'>({headerList.length})</div>
</div>
<div className='flex items-center'>
<button className='btn btn-sm btn-primary'>Add</button>
</div>
</div>
</div>
</div>
);
};

View File

@ -0,0 +1,36 @@
import { useAppStore } from '../store';
type LabelProps = {
title: string;
children?: any;
};
export const Label = (props: LabelProps) => {
const { title } = props;
return (
<div className='flex'>
<div className='font-medium'>{title}:</div>
<div className='ml-2 line-clamp-3'>{props.children}</div>
</div>
);
};
export const Left = () => {
const appStore = useAppStore();
return (
<div className='flex-shrink-0'>
<div className='px-4 py-2 max-h-[300px] overflow-auto scrollbar'>
<Label title='Title'>{appStore.data?.title}</Label>
<Label title='Description'>{appStore.data?.description}</Label>
</div>
<div className='h-0.5 bg-gray-500'></div>
<div className='mt-4 px-2 text-xs'>
{appStore.nodes?.map?.((node, index) => {
return (
<div className='hover:bg-gray-300 p-2 cursor-pointer' key={node.id}>
{node.id}
</div>
);
})}
</div>
</div>
);
};

View File

@ -0,0 +1,45 @@
import { query } from '@/modules';
import { message } from 'antd';
import { create } from 'zustand';
type Node = {
id: string;
type: string;
data: {
cid: string;
};
};
type AppStore = {
id: string;
setId: (id: string) => void;
getData: (id: string) => Promise<any>;
nodes: Node[];
data: any;
};
export const useAppStore = create<AppStore>((set, get) => ({
id: '',
setId: (id: string) => set({ id }),
data: {},
nodes: [],
getData: async (id: string) => {
console.log('getData');
if (!id) {
message.error('Invalid id');
return;
}
set({ id });
const loaded = message.loading('Loading...', 0);
const res = await query.post({
path: 'page',
key: 'get',
id,
});
loaded();
if (res.code === 200) {
console.log(res.data);
const data = res.data;
const nodes = data?.data?.nodes;
set({ data: data, nodes });
}
},
}));

View File

@ -3,6 +3,8 @@ import { List } from './edit/List';
import { Main } from './layouts'; import { Main } from './layouts';
import { App as FlowApp } from './flow'; import { App as FlowApp } from './flow';
import { Deck } from './deck'; import { Deck } from './deck';
import { App as PanelApp } from './app';
export const App = () => { export const App = () => {
return ( return (
<Routes> <Routes>
@ -11,6 +13,7 @@ export const App = () => {
<Route path='edit/list' element={<List />} /> <Route path='edit/list' element={<List />} />
<Route path='flow/:id' element={<FlowApp />} /> <Route path='flow/:id' element={<FlowApp />} />
<Route path='deck/:id' element={<Deck />} /> <Route path='deck/:id' element={<Deck />} />
<Route path='app/:id' element={<PanelApp />} />
<Route path='*' element={'Not Found'}></Route> <Route path='*' element={'Not Found'}></Route>
</Route> </Route>
</Routes> </Routes>