diff --git a/package.json b/package.json index ee0e8ec..cc83bef 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "dependencies": { "@ant-design/charts": "^1.4.2", "@ant-design/icons": "^5.2.5", + "@monaco-editor/react": "^4.6.0", "@paralleldrive/cuid2": "^2.2.2", "@prisma/client": "^5.4.2", "@tanstack/react-query": "^4.33.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ddf6c1d..6035179 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,6 +7,9 @@ dependencies: '@ant-design/icons': specifier: ^5.2.5 version: 5.2.5(react-dom@18.2.0)(react@18.2.0) + '@monaco-editor/react': + specifier: ^4.6.0 + version: 4.6.0(monaco-editor@0.45.0)(react-dom@18.2.0)(react@18.2.0) '@paralleldrive/cuid2': specifier: ^2.2.2 version: 2.2.2 @@ -1760,6 +1763,28 @@ packages: engines: {node: '>=6.0.0'} dev: false + /@monaco-editor/loader@1.4.0(monaco-editor@0.45.0): + resolution: {integrity: sha512-00ioBig0x642hytVspPl7DbQyaSWRaolYie/UFNjoTdvoKPzo6xrXLhTk9ixgIKcLH5b5vDOjVNiGyY+uDCUlg==} + peerDependencies: + monaco-editor: '>= 0.21.0 < 1' + dependencies: + monaco-editor: 0.45.0 + state-local: 1.0.7 + dev: false + + /@monaco-editor/react@4.6.0(monaco-editor@0.45.0)(react-dom@18.2.0)(react@18.2.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 + dependencies: + '@monaco-editor/loader': 1.4.0(monaco-editor@0.45.0) + monaco-editor: 0.45.0 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@noble/hashes@1.3.2: resolution: {integrity: sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==} engines: {node: '>= 16'} @@ -6513,6 +6538,10 @@ packages: resolution: {integrity: sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==} dev: false + /monaco-editor@0.45.0: + resolution: {integrity: sha512-mjv1G1ZzfEE3k9HZN0dQ2olMdwIfaeAAjFiwNprLfYNRSz7ctv9XuCT7gPtBGrMUeV1/iZzYKj17Khu1hxoHOA==} + dev: false + /morgan@1.10.0: resolution: {integrity: sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==} engines: {node: '>= 0.8.0'} @@ -9063,6 +9092,10 @@ packages: stacktrace-gps: 3.1.2 dev: false + /state-local@1.0.7: + resolution: {integrity: sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==} + dev: false + /statuses@2.0.1: resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} engines: {node: '>= 0.8'} diff --git a/src/client/components/CodeEditor/index.tsx b/src/client/components/CodeEditor/index.tsx new file mode 100644 index 0000000..b176af6 --- /dev/null +++ b/src/client/components/CodeEditor/index.tsx @@ -0,0 +1,5 @@ +import { lazy } from 'react'; + +export const CodeEditor = lazy(() => + import('./main').then((m) => ({ default: m.CodeEditor })) +); diff --git a/src/client/components/CodeEditor/lib/sandbox.ts b/src/client/components/CodeEditor/lib/sandbox.ts new file mode 100644 index 0000000..9863c20 --- /dev/null +++ b/src/client/components/CodeEditor/lib/sandbox.ts @@ -0,0 +1,48 @@ +export const sandboxGlobal = ` +interface AxiosConfig { + url?: string; + method?: + | 'get' | 'GET' + | 'delete' | 'DELETE' + | 'head' | 'HEAD' + | 'options' | 'OPTIONS' + | 'post' | 'POST' + | 'put' | 'PUT' + | 'patch' | 'PATCH' + | 'purge' | 'PURGE' + | 'link' | 'LINK' + | 'unlink' | 'UNLINK'; + baseURL?: string; + headers?: Record; + params?: any; + data?: any; + timeout?: number; + withCredentials?: boolean; + auth?: { + username: string; + password: string; + }; + responseType?: + | 'arraybuffer' + | 'blob' + | 'document' + | 'json' + | 'text' + | 'stream'; + responseEncoding?: string; + xsrfCookieName?: string; + xsrfHeaderName?: string; + maxContentLength?: number; + proxy?: { + host: string; + port: number; + auth?: { + username: string; + password: string; + }; + protocol?: string; + } | false; +} + +const request = async (config: AxiosConfig) => {} +`; diff --git a/src/client/components/CodeEditor/main.tsx b/src/client/components/CodeEditor/main.tsx new file mode 100644 index 0000000..f7ba808 --- /dev/null +++ b/src/client/components/CodeEditor/main.tsx @@ -0,0 +1,33 @@ +import Editor, { Monaco } from '@monaco-editor/react'; +import React from 'react'; +import { useSettingsStore } from '../../store/settings'; +import { useEvent } from '../../hooks/useEvent'; +import { sandboxGlobal } from './lib/sandbox'; + +interface CodeEditorProps { + height?: string | number; + value?: string; + onChange?: (code: string) => void; +} +export const CodeEditor: React.FC = React.memo((props) => { + const colorScheme = useSettingsStore((state) => state.colorScheme); + const theme = colorScheme === 'dark' ? 'vs-dark' : 'light'; + + const handleEditorWillMount = useEvent((monaco: Monaco) => { + monaco.languages.typescript.javascriptDefaults.addExtraLib( + sandboxGlobal, + 'global.ts' + ); + }); + + return ( + props.onChange?.(val ?? '')} + beforeMount={handleEditorWillMount} + /> + ); +}); diff --git a/src/client/components/monitor/provider/custom.tsx b/src/client/components/monitor/provider/custom.tsx index c040d9d..71444c7 100644 --- a/src/client/components/monitor/provider/custom.tsx +++ b/src/client/components/monitor/provider/custom.tsx @@ -1,6 +1,7 @@ -import { Form, Input } from 'antd'; +import { Button, Form } from 'antd'; import React from 'react'; import { MonitorProvider } from './types'; +import { CodeEditor } from '../../CodeEditor'; export const MonitorCustom: React.FC = React.memo(() => { return ( @@ -10,7 +11,7 @@ export const MonitorCustom: React.FC = React.memo(() => { name={['payload', 'code']} rules={[{ required: true }]} > - + );