From 43110dc4659087ae2c437f75f0e840a2eb25728f Mon Sep 17 00:00:00 2001 From: liulei Date: Wed, 18 Jan 2023 19:34:07 +0800 Subject: [PATCH 01/68] =?UTF-8?q?feat:=20=E5=88=9D=E5=A7=8B=E5=8C=96=20sta?= =?UTF-8?q?te=20manager?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...pFileContext.tsx => AppManagerContext.tsx} | 0 packages/core/src/contexts/index.ts | 2 +- .../render/src/components/ReactRender.tsx | 5 +-- .../render/src/components/WidgetVirtual.tsx | 7 +--- packages/state-manager/package.json | 12 +++++++ packages/state-manager/src/AppState/index.ts | 33 +++++++++++++++++++ packages/state-manager/src/PageState/index.ts | 21 ++++++++++++ .../state-manager/src/StateManager/index.ts | 12 +++++++ .../state-manager/src/WidgetState/index.ts | 25 ++++++++++++++ packages/state-manager/src/index.ts | 4 +++ .../src/features/app/routers/App.tsx | 1 - 11 files changed, 110 insertions(+), 12 deletions(-) rename packages/core/src/contexts/{AppFileContext.tsx => AppManagerContext.tsx} (100%) create mode 100644 packages/state-manager/package.json create mode 100644 packages/state-manager/src/AppState/index.ts create mode 100644 packages/state-manager/src/PageState/index.ts create mode 100644 packages/state-manager/src/StateManager/index.ts create mode 100644 packages/state-manager/src/WidgetState/index.ts create mode 100644 packages/state-manager/src/index.ts diff --git a/packages/core/src/contexts/AppFileContext.tsx b/packages/core/src/contexts/AppManagerContext.tsx similarity index 100% rename from packages/core/src/contexts/AppFileContext.tsx rename to packages/core/src/contexts/AppManagerContext.tsx diff --git a/packages/core/src/contexts/index.ts b/packages/core/src/contexts/index.ts index 875d119..83c0d52 100644 --- a/packages/core/src/contexts/index.ts +++ b/packages/core/src/contexts/index.ts @@ -1,2 +1,2 @@ export * from './AppFactoryContext' -export * from './AppFileContext' +export * from './AppManagerContext' diff --git a/packages/render/src/components/ReactRender.tsx b/packages/render/src/components/ReactRender.tsx index 885d40a..433d0fb 100644 --- a/packages/render/src/components/ReactRender.tsx +++ b/packages/render/src/components/ReactRender.tsx @@ -1,6 +1,6 @@ import { ConfigProvider } from 'antd' import zhCN from 'antd/locale/zh_CN' -import { FC, useContext, useEffect, useState } from 'react' +import { FC, useContext, useState } from 'react' import * as React from 'react' import { AppFactoryContext, AppManagerProvider } from '@modou/core' @@ -16,9 +16,6 @@ export const ReactRender: FC = (props) => { const [appManager, updateAppManager] = useState() const [file, updateFile] = useState() useInitRender({ ...props, updateAppManager, updateFile }) - useEffect(() => { - console.log('123') - }) if (!file || !appManager) { return null } diff --git a/packages/render/src/components/WidgetVirtual.tsx b/packages/render/src/components/WidgetVirtual.tsx index 3fc6b8c..533d333 100644 --- a/packages/render/src/components/WidgetVirtual.tsx +++ b/packages/render/src/components/WidgetVirtual.tsx @@ -4,7 +4,7 @@ import { TextNode, baseParse, } from '@vue/compiler-core' -import { useMemoizedFn, useMount, useUnmount } from 'ahooks' +import { useMemoizedFn, useMount } from 'ahooks' import { flatten } from 'flat' import { get, isFunction, keys, set } from 'lodash' import { FC, useContext, useEffect, useRef } from 'react' @@ -182,11 +182,6 @@ const _WidgetVirtual: FC<{ }) }) - useUnmount(() => { - // FIXME - // Object.values(watchStopsRef.current).forEach((stop) => stop()) - }) - // FIXME 会导致重新渲染 // FIXME 完善组件类型 return ( diff --git a/packages/state-manager/package.json b/packages/state-manager/package.json new file mode 100644 index 0000000..7cb3e24 --- /dev/null +++ b/packages/state-manager/package.json @@ -0,0 +1,12 @@ +{ + "name": "@modou/state-manager", + "version": "0.0.1", + "description": "", + "main": "src", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/packages/state-manager/src/AppState/index.ts b/packages/state-manager/src/AppState/index.ts new file mode 100644 index 0000000..0f415e2 --- /dev/null +++ b/packages/state-manager/src/AppState/index.ts @@ -0,0 +1,33 @@ +import { makeAutoObservable } from '@modou/reactivity' + +import { PageState } from '../PageState' + +interface User { + name: string + email: string + id: string +} + +export class AppState { + constructor({ user, id, name }: { user: User; id: string; name: string }) { + this.state = { + id, + name, + user, + } + makeAutoObservable(this) + } + + state: { + id: string + name: string + user: User + } + + subState: { + page: Map + } = { + page: new Map(), + } + // pages: [] +} diff --git a/packages/state-manager/src/PageState/index.ts b/packages/state-manager/src/PageState/index.ts new file mode 100644 index 0000000..bf450d6 --- /dev/null +++ b/packages/state-manager/src/PageState/index.ts @@ -0,0 +1,21 @@ +import { makeAutoObservable } from '@modou/reactivity' + +import { WidgetState } from '../WidgetState' + +export class PageState { + constructor({ id, name }: { id: string; name: string }) { + this.state = { id, name } + makeAutoObservable(this) + } + + state: { + id: string + name: string + } + + subState: { + widget: Map + } = { + widget: new Map(), + } +} diff --git a/packages/state-manager/src/StateManager/index.ts b/packages/state-manager/src/StateManager/index.ts new file mode 100644 index 0000000..52240b4 --- /dev/null +++ b/packages/state-manager/src/StateManager/index.ts @@ -0,0 +1,12 @@ +import { makeAutoObservable } from '@modou/reactivity' + +import { AppState } from '../AppState' + +export class StateManager { + constructor(appState: AppState) { + this.app = appState + makeAutoObservable(this) + } + + app: AppState +} diff --git a/packages/state-manager/src/WidgetState/index.ts b/packages/state-manager/src/WidgetState/index.ts new file mode 100644 index 0000000..f1dbe7e --- /dev/null +++ b/packages/state-manager/src/WidgetState/index.ts @@ -0,0 +1,25 @@ +import { isFunction } from 'lodash' + +import { makeAutoObservable } from '@modou/reactivity' + +type BaseWidgetState = Record +export class WidgetState { + // TODO 定义 State 类型 + constructor(state: BaseWidgetState) { + this.state = state + makeAutoObservable(this) + } + + // TODO 完善 Widget State 定义 + state: BaseWidgetState + + updateState( + state: BaseWidgetState | ((oldState: BaseWidgetState) => BaseWidgetState), + ) { + if (isFunction(state)) { + this.state = state(this.state) + } else { + this.state = state + } + } +} diff --git a/packages/state-manager/src/index.ts b/packages/state-manager/src/index.ts new file mode 100644 index 0000000..9e9c101 --- /dev/null +++ b/packages/state-manager/src/index.ts @@ -0,0 +1,4 @@ +export { AppState } from './AppState' +export { PageState } from './PageState' +export { WidgetState } from './WidgetState' +export { StateManager } from './StateManager' diff --git a/websites/workspace/src/features/app/routers/App.tsx b/websites/workspace/src/features/app/routers/App.tsx index 375e965..5702bc9 100644 --- a/websites/workspace/src/features/app/routers/App.tsx +++ b/websites/workspace/src/features/app/routers/App.tsx @@ -17,7 +17,6 @@ import { AppManagerProvider } from '@modou/core' import { mcss } from '@modou/css-in-js' import { AppManager } from '@modou/meta-vfs' import { runInAction } from '@modou/reactivity' -import { observer } from '@modou/reactivity-react' import { ModuleManager } from '../components' import { AppHeader } from '../components/AppHeader' From 20c8fcf8be0f2db1c16e4f0fb37418e3c68cb09b Mon Sep 17 00:00:00 2001 From: liulei Date: Fri, 20 Jan 2023 20:46:22 +0800 Subject: [PATCH 02/68] =?UTF-8?q?feat:=20=E5=88=9D=E5=A7=8B=E5=8C=96?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E7=AE=A1=E7=90=86=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/canvas-designer/src/utils/index.ts | 6 - packages/core/src/utils/index.ts | 7 -- packages/render/package.json | 5 +- .../render/src/components/ReactRender.tsx | 26 ++-- .../src/components/ReactRenderTolerant.tsx | 2 +- .../render/src/components/WidgetVirtual.tsx | 115 ++++-------------- packages/render/src/contexts/index.ts | 1 + packages/render/src/hooks/index.ts | 1 + packages/render/src/hooks/useInitRender.ts | 21 ++-- .../render/src/hooks/useInitStateManager.ts | 28 +++++ packages/render/src/utils/evaluate.ts | 21 ++++ packages/render/src/utils/index.ts | 6 - packages/state-manager/src/AppState/index.ts | 20 ++- packages/state-manager/src/PageState/index.ts | 15 ++- .../state-manager/src/StateManager/index.ts | 11 +- .../state-manager/src/WidgetState/index.ts | 25 +++- .../src/contexts/StateManagerContext.tsx | 26 ++++ packages/state-manager/src/contexts/index.ts | 1 + pnpm-lock.yaml | 45 +------ 19 files changed, 195 insertions(+), 187 deletions(-) create mode 100644 packages/render/src/contexts/index.ts create mode 100644 packages/render/src/hooks/useInitStateManager.ts create mode 100644 packages/render/src/utils/evaluate.ts create mode 100644 packages/state-manager/src/contexts/StateManagerContext.tsx create mode 100644 packages/state-manager/src/contexts/index.ts diff --git a/packages/canvas-designer/src/utils/index.ts b/packages/canvas-designer/src/utils/index.ts index 1d11a87..8b62a4d 100644 --- a/packages/canvas-designer/src/utils/index.ts +++ b/packages/canvas-designer/src/utils/index.ts @@ -1,9 +1,3 @@ -import { name } from '../../package.json' - -export const generateRecoilKey = (key: string): string => { - return `@${name}/${key}` -} - export const getWidgetIdFromElement = (element: HTMLElement): string => { return element?.dataset?.widgetId ?? '' } diff --git a/packages/core/src/utils/index.ts b/packages/core/src/utils/index.ts index f8d0e29..019a5f2 100644 --- a/packages/core/src/utils/index.ts +++ b/packages/core/src/utils/index.ts @@ -1,18 +1,11 @@ import { customAlphabet } from 'nanoid' -import { name } from '../../package.json' import { WidgetGroupEnum } from '../types' const nanoid = customAlphabet('abcdefghigklmnopqrstuvwxyz', 12) export const generateId = (size: number = 12): string => { return nanoid(size) } -export const generateRecoilKey = ( - key: string, - packageName: string = name, -): string => { - return `@${packageName}/${key}` -} export const getWidgetGroupLabel = (group: WidgetGroupEnum) => { switch (group) { diff --git a/packages/render/package.json b/packages/render/package.json index 0658d4c..b8a28dc 100644 --- a/packages/render/package.json +++ b/packages/render/package.json @@ -8,5 +8,8 @@ }, "keywords": [], "author": "", - "license": "ISC" + "license": "ISC", + "dependencies": { + "@modou/state-manager": "workspace:^0.0.1" + } } diff --git a/packages/render/src/components/ReactRender.tsx b/packages/render/src/components/ReactRender.tsx index 433d0fb..6c42c72 100644 --- a/packages/render/src/components/ReactRender.tsx +++ b/packages/render/src/components/ReactRender.tsx @@ -1,31 +1,35 @@ import { ConfigProvider } from 'antd' import zhCN from 'antd/locale/zh_CN' -import { FC, useContext, useState } from 'react' +import { FC, useContext } from 'react' import * as React from 'react' import { AppFactoryContext, AppManagerProvider } from '@modou/core' -import { AppManager, PageFile } from '@modou/meta-vfs' +import { StateManagerProvider } from '@modou/state-manager/src/contexts' -import { CanvasFileContextProvider } from '../contexts/CanvasFileContext' -import { useInitRender } from '../hooks' +import { CanvasFileContextProvider } from '../contexts' +import { useInitRender, useInitStateManager } from '../hooks' import { MoDouRenderProps } from '../types' import { ReactRenderTolerant } from './ReactRenderTolerant' +// TODO 支持页面的 State 缓存 比如详情页面回退到列表页面 export const ReactRender: FC = (props) => { const appFactory = useContext(AppFactoryContext) - const [appManager, updateAppManager] = useState() - const [file, updateFile] = useState() - useInitRender({ ...props, updateAppManager, updateFile }) - if (!file || !appManager) { + const { file, appManager } = useInitRender() + const { stateManager } = useInitStateManager({ app: appManager?.app, file }) + console.log('stateManager', file, appManager, stateManager) + if (!file || !appManager || !stateManager) { return null } return ( + {/* TODO 去除点(.)保持跟其他Context统一 */} - - - + + + + + diff --git a/packages/render/src/components/ReactRenderTolerant.tsx b/packages/render/src/components/ReactRenderTolerant.tsx index 3406fae..0683e4a 100644 --- a/packages/render/src/components/ReactRenderTolerant.tsx +++ b/packages/render/src/components/ReactRenderTolerant.tsx @@ -6,7 +6,7 @@ import { useAppManager } from '@modou/core' import { mcss } from '@modou/css-in-js' import { observer } from '@modou/reactivity-react' -import { useCanvasFile } from '../contexts/CanvasFileContext' +import { useCanvasFile } from '../contexts' import { MoDouRenderProps } from '../types' import { WidgetVirtual } from './WidgetVirtual' diff --git a/packages/render/src/components/WidgetVirtual.tsx b/packages/render/src/components/WidgetVirtual.tsx index 533d333..1e12ead 100644 --- a/packages/render/src/components/WidgetVirtual.tsx +++ b/packages/render/src/components/WidgetVirtual.tsx @@ -4,63 +4,38 @@ import { TextNode, baseParse, } from '@vue/compiler-core' -import { useMemoizedFn, useMount } from 'ahooks' +import { useMount } from 'ahooks' import { flatten } from 'flat' -import { get, isFunction, keys, set } from 'lodash' -import { FC, useContext, useEffect, useRef } from 'react' +import { get, keys, set } from 'lodash' +import { FC, useContext, useRef } from 'react' import * as React from 'react' -import { AppFactoryContext, WidgetBaseProps, useAppManager } from '@modou/core' +import { AppFactoryContext, useAppManager } from '@modou/core' import { IReactionDisposer, autorun, - makeAutoObservable, runInAction, toJS, } from '@modou/reactivity' import { observer, useLocalObservable } from '@modou/reactivity-react' +import { WidgetState } from '@modou/state-manager' +import { useStateManager } from '@modou/state-manager/src/contexts' import { ParseNodeTypes } from '../types' - -const EXPRESSION_REG = /[\s\S]*{{[\s\S]*}}[\s\S]*/m -const isExpression = (str: unknown): str is string => { - return typeof str === 'string' && EXPRESSION_REG.test(str) -} -const evalExpression = (expression: string) => { - try { - // eslint-disable-next-line @typescript-eslint/no-implied-eval,no-new-func,no-useless-call - return new Function( - 'state', - `with(state){ - return ${expression} - }`, - ).call(null, store.state) - } catch (e) { - return String((e as SyntaxError)?.message) ?? 'Error' - } -} - -class Store { - constructor() { - makeAutoObservable(this) - } - - state: Record = {} - props: Record = {} -} - -const store = new Store() - -// const ErrorWidget: FC = () => { -// return
Error
-// } +import { evalExpression, isExpression } from '../utils/evaluate' const _WidgetVirtual: FC<{ widgetId: string }> = ({ widgetId }) => { const { appManager } = useAppManager() + const { canvasState } = useStateManager() const widget = appManager.widgetMap.get(widgetId)! const appFactory = useContext(AppFactoryContext) + let widgetState = canvasState.subState.widget[widget.meta.id] + if (!widgetState) { + widgetState = new WidgetState(widget, appFactory) + canvasState.subState.widget[widget.meta.id] = widgetState + } const widgetDef = appFactory.widgetByType[widget.meta.type] // TODO any 替换 state 定义 const WidgetComponent = widgetDef.component @@ -94,62 +69,17 @@ const _WidgetVirtual: FC<{ }, })) - // reactive state - if (!get(store.state, widgetId)) { - runInAction(() => { - set(store.state, widgetId, { - ...widget.meta.slots, - ...widgetDef.metadata.initState(widget.meta), - }) - }) - } - - // reactive props - if (!get(store.props, widgetId)) { - runInAction(() => { - set(store.props, widgetId, widget.meta.props) - }) - } - - // update reactive props - useEffect(() => { - runInAction(() => { - set(store.props, widgetId, widget.meta.props) - }) - }, [widget.meta.props, widgetId]) - - // TODO 优化类型 - const updateWidgetState = useMemoizedFn( - (newState: S | ((prevState: S) => S)) => { - runInAction(() => { - if (isFunction(newState)) { - set(store.state, widgetId, newState(get(store.state, widgetId))) - } else { - set(store.state, widgetId, newState) - } - }) - }, - ) - - useEffect(() => { - // FIXME 为什么会渲染两遍 - updateWidgetState<{}>((prev) => ({ - ...prev, - ...widget.meta.props, - })) - }, [updateWidgetState, widget.meta.props]) - const watchStopsRef = useRef>({}) useMount(() => { - const flattenStateKeys = keys(flatten(store.state[widgetId])) + const flattenStateKeys = keys(flatten(widgetState.state)) flattenStateKeys.forEach((path) => { if (Reflect.has(watchStopsRef.current, path)) { return } watchStopsRef.current[path] = autorun(() => { - const fullPath = `${widgetId}.${path}` - const rawPropVal = get(store.props, fullPath) + const fullPath = `${path}` + const rawPropVal = get(widget.meta.props, fullPath) if (isExpression(rawPropVal)) { const ast = baseParse(rawPropVal) const expression = `\`${ast.children @@ -173,10 +103,14 @@ const _WidgetVirtual: FC<{ }) .join('')}\`` runInAction(() => { - set(store.state, fullPath, evalExpression(expression)) + set( + widgetState.state, + fullPath, + evalExpression(expression, canvasState), + ) }) } else { - // set(store.state, `${widgetId}.${path}`, rawPropVal) + set(widgetState.state, `${path}`, rawPropVal) } }) }) @@ -184,10 +118,11 @@ const _WidgetVirtual: FC<{ // FIXME 会导致重新渲染 // FIXME 完善组件类型 + // console.log('toJS(widgetState)', toJS(widgetState.state)) return ( diff --git a/packages/render/src/contexts/index.ts b/packages/render/src/contexts/index.ts new file mode 100644 index 0000000..322a72b --- /dev/null +++ b/packages/render/src/contexts/index.ts @@ -0,0 +1 @@ +export * from './CanvasFileContext' diff --git a/packages/render/src/hooks/index.ts b/packages/render/src/hooks/index.ts index 95253b2..5faee6d 100644 --- a/packages/render/src/hooks/index.ts +++ b/packages/render/src/hooks/index.ts @@ -1 +1,2 @@ export { useInitRender } from './useInitRender' +export { useInitStateManager } from './useInitStateManager' diff --git a/packages/render/src/hooks/useInitRender.ts b/packages/render/src/hooks/useInitRender.ts index 6e09e04..3d3093d 100644 --- a/packages/render/src/hooks/useInitRender.ts +++ b/packages/render/src/hooks/useInitRender.ts @@ -1,18 +1,16 @@ import { useMemoizedFn } from 'ahooks' -import { useEffect } from 'react' +import { useEffect, useState } from 'react' + +import { AppManager, PageFile } from '@modou/meta-vfs' import { APP_MANAGER_SYMBOL, FILE_SYMBOL } from '../constants' -import { MoDouRenderProps } from '../types' import { ReactRenderHost } from '../utils' import { UpdateAppManager, UpdateFile } from '../utils/ReactRenderHost' -export const useInitRender = ({ - updateFile, - updateAppManager, -}: { - updateAppManager: UpdateAppManager - updateFile: UpdateFile -} & MoDouRenderProps) => { +export const useInitRender = () => { + // TODO 判断 host type 浏览器 or 模拟器 + const [appManager, updateAppManager] = useState() + const [file, updateFile] = useState() const _updateAppManager: UpdateAppManager = useMemoizedFn((appManager) => { if (!Reflect.get(window, APP_MANAGER_SYMBOL)) { Reflect.set(window, APP_MANAGER_SYMBOL, appManager) @@ -42,4 +40,9 @@ export const useInitRender = ({ updateFile(Reflect.get(window, FILE_SYMBOL)) } }) + + return { + file, + appManager, + } } diff --git a/packages/render/src/hooks/useInitStateManager.ts b/packages/render/src/hooks/useInitStateManager.ts new file mode 100644 index 0000000..ef50ea0 --- /dev/null +++ b/packages/render/src/hooks/useInitStateManager.ts @@ -0,0 +1,28 @@ +import { useEffect, useState } from 'react' + +import { AppFile, PageFile } from '@modou/meta-vfs' +import { AppState, PageState, StateManager } from '@modou/state-manager' + +export const useInitStateManager = ({ + app, + file, +}: { + app?: AppFile + file?: PageFile +}) => { + const [stateManager, setStateManager] = useState() + useEffect(() => { + if (!app || !file) { + return + } + setStateManager( + new StateManager({ + appState: new AppState(app), + canvasState: new PageState(file), + }), + ) + }, [app, file]) + return { + stateManager, + } +} diff --git a/packages/render/src/utils/evaluate.ts b/packages/render/src/utils/evaluate.ts new file mode 100644 index 0000000..6277bce --- /dev/null +++ b/packages/render/src/utils/evaluate.ts @@ -0,0 +1,21 @@ +import { PageState } from '@modou/state-manager' + +const EXPRESSION_REG = /[\s\S]*{{[\s\S]*}}[\s\S]*/m + +export const isExpression = (str: unknown): str is string => { + return typeof str === 'string' && EXPRESSION_REG.test(str) +} +// TODO 完善 store 类型 +export const evalExpression = (expression: string, canvasState: PageState) => { + try { + // eslint-disable-next-line @typescript-eslint/no-implied-eval,no-new-func,no-useless-call + return new Function( + 'state', + `with(state){ + return ${expression} + }`, + ).call(null, canvasState.subState.widget) + } catch (e) { + return String((e as SyntaxError)?.message) ?? 'Error' + } +} diff --git a/packages/render/src/utils/index.ts b/packages/render/src/utils/index.ts index caa13cc..f12e8f8 100644 --- a/packages/render/src/utils/index.ts +++ b/packages/render/src/utils/index.ts @@ -1,7 +1 @@ -import { name } from '../../package.json' - export { ReactRenderHost } from './ReactRenderHost' - -export const generateRecoilKey = (key: string): string => { - return `@${name}/${key}` -} diff --git a/packages/state-manager/src/AppState/index.ts b/packages/state-manager/src/AppState/index.ts index 0f415e2..93a46e2 100644 --- a/packages/state-manager/src/AppState/index.ts +++ b/packages/state-manager/src/AppState/index.ts @@ -1,3 +1,4 @@ +import { AppFile } from '@modou/meta-vfs' import { makeAutoObservable } from '@modou/reactivity' import { PageState } from '../PageState' @@ -9,15 +10,22 @@ interface User { } export class AppState { - constructor({ user, id, name }: { user: User; id: string; name: string }) { + constructor(file: AppFile) { + this.file = file this.state = { - id, - name, - user, + id: file.meta.id, + name: file.meta.name, + user: { + name: '张三', + email: 'zhangsan@gmail.com', + id: 'zhangsan', + }, } makeAutoObservable(this) } + file: AppFile + state: { id: string name: string @@ -25,9 +33,9 @@ export class AppState { } subState: { - page: Map + page: Record } = { - page: new Map(), + page: {}, } // pages: [] } diff --git a/packages/state-manager/src/PageState/index.ts b/packages/state-manager/src/PageState/index.ts index bf450d6..dc7184a 100644 --- a/packages/state-manager/src/PageState/index.ts +++ b/packages/state-manager/src/PageState/index.ts @@ -1,21 +1,28 @@ +import { PageFile } from '@modou/meta-vfs' import { makeAutoObservable } from '@modou/reactivity' import { WidgetState } from '../WidgetState' export class PageState { - constructor({ id, name }: { id: string; name: string }) { - this.state = { id, name } + constructor(file: PageFile) { + this.file = file + this.state = { + id: file.meta.id, + name: file.meta.name, + } makeAutoObservable(this) } + file: PageFile + state: { id: string name: string } subState: { - widget: Map + widget: Record } = { - widget: new Map(), + widget: {}, } } diff --git a/packages/state-manager/src/StateManager/index.ts b/packages/state-manager/src/StateManager/index.ts index 52240b4..e88c91e 100644 --- a/packages/state-manager/src/StateManager/index.ts +++ b/packages/state-manager/src/StateManager/index.ts @@ -1,12 +1,21 @@ import { makeAutoObservable } from '@modou/reactivity' import { AppState } from '../AppState' +import { PageState } from '../PageState' export class StateManager { - constructor(appState: AppState) { + constructor({ + appState, + canvasState, + }: { + appState: AppState + canvasState: PageState + }) { this.app = appState + this.canvas = canvasState makeAutoObservable(this) } app: AppState + canvas: PageState } diff --git a/packages/state-manager/src/WidgetState/index.ts b/packages/state-manager/src/WidgetState/index.ts index f1dbe7e..eefeed0 100644 --- a/packages/state-manager/src/WidgetState/index.ts +++ b/packages/state-manager/src/WidgetState/index.ts @@ -1,15 +1,32 @@ import { isFunction } from 'lodash' +import { AppFactory } from '@modou/core' +import { WidgetFile } from '@modou/meta-vfs' import { makeAutoObservable } from '@modou/reactivity' -type BaseWidgetState = Record +// TODO 完善类型定义 +type BaseWidgetState = Record & { + instance: { + id: string + widgetId: string + initialized: boolean + } +} export class WidgetState { - // TODO 定义 State 类型 - constructor(state: BaseWidgetState) { - this.state = state + // TODO 定义 State 类型 & 提取 appFactory 到mobx + // TODO 尝试 把 widgetDef 放到 file 上 + constructor(file: WidgetFile, appFactory: AppFactory) { + const widgetDef = appFactory.widgetByType[file.meta.type] + this.file = file + this.state = { + ...file.meta.props, + ...widgetDef.metadata.initState(file.meta), + } as unknown as BaseWidgetState makeAutoObservable(this) } + file: WidgetFile + // TODO 完善 Widget State 定义 state: BaseWidgetState diff --git a/packages/state-manager/src/contexts/StateManagerContext.tsx b/packages/state-manager/src/contexts/StateManagerContext.tsx new file mode 100644 index 0000000..8d6e1a2 --- /dev/null +++ b/packages/state-manager/src/contexts/StateManagerContext.tsx @@ -0,0 +1,26 @@ +import { FC, ReactNode, createContext, useContext } from 'react' + +import { StateManager } from '../StateManager' + +const StateManagerContext = createContext(null) +export const StateManagerProvider: FC<{ + value: StateManager + children: ReactNode +}> = ({ value, children }) => { + return ( + + {children} + + ) +} + +export const useStateManager = () => { + const stateManager = useContext( + StateManagerContext, + ) as unknown as StateManager + return { + stateManager, + appState: stateManager.app, + canvasState: stateManager.canvas, + } +} diff --git a/packages/state-manager/src/contexts/index.ts b/packages/state-manager/src/contexts/index.ts new file mode 100644 index 0000000..8fe0bb1 --- /dev/null +++ b/packages/state-manager/src/contexts/index.ts @@ -0,0 +1 @@ +export * from './StateManagerContext' diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5aabfff..9ec0c76 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -62,8 +62,6 @@ importers: react-json-view: ^1.21.3 react-router-dom: ^6.3.0 reactflow: ^11.3.0 - recoil: ^0.7.5 - recoil-sync: ^0.1.1 rollup-plugin-visualizer: ^5.8.2 ts-pattern: ^4.0.5 typescript: ^4.7.4 @@ -101,8 +99,6 @@ importers: react-json-view: 1.21.3_rj7ozvcq3uehdlnj3cbwzbi5ce react-router-dom: 6.4.2_biqbaboplfbrettd7655fr4n2y reactflow: 11.3.0_rekktpi253ghbdqoi5qfkp32ay - recoil: 0.7.6_biqbaboplfbrettd7655fr4n2y - recoil-sync: 0.1.1_recoil@0.7.6 ts-pattern: 4.0.5 devDependencies: '@emotion/babel-plugin': 11.10.5 @@ -333,7 +329,10 @@ importers: '@lowcode-modou/zod-to-json-schema': 0.0.19_@lowcode-modou+zod@0.0.14 packages/render: - specifiers: {} + specifiers: + '@modou/state-manager': workspace:^0.0.1 + dependencies: + '@modou/state-manager': link:../state-manager packages/setters: specifiers: {} @@ -9155,10 +9154,6 @@ packages: resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} dev: true - /hamt_plus/1.0.2: - resolution: {integrity: sha512-t2JXKaehnMb9paaYA7J0BX8QQAY8lwfQ9Gjf4pg/mk4krt+cmwmU652HOoWonf+7+EQV97ARPMhhVgU1ra2GhA==} - dev: false - /handle-thing/2.0.1: resolution: {integrity: sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==} dev: true @@ -14080,33 +14075,6 @@ packages: engines: {node: '>= 12.13.0'} dev: true - /recoil-sync/0.1.1_recoil@0.7.6: - resolution: {integrity: sha512-+ZVMT4sLIyUFif7EeIlJjOLdiMarF3M0E9uJWQG9vK5yoFLrXzY8qR0fzIH36ofOwpPUmX4fw90YkV29X3Ts+w==} - peerDependencies: - recoil: '>=0.7.3' - dependencies: - '@recoiljs/refine': 0.1.1 - recoil: 0.7.6_biqbaboplfbrettd7655fr4n2y - transit-js: 0.8.874 - dev: false - - /recoil/0.7.6_biqbaboplfbrettd7655fr4n2y: - resolution: {integrity: sha512-hsBEw7jFdpBCY/tu2GweiyaqHKxVj6EqF2/SfrglbKvJHhpN57SANWvPW+gE90i3Awi+A5gssOd3u+vWlT+g7g==} - peerDependencies: - react: '>=16.13.1' - react-dom: '*' - react-native: '*' - peerDependenciesMeta: - react-dom: - optional: true - react-native: - optional: true - dependencies: - hamt_plus: 1.0.2 - react: 18.2.0 - react-dom: 18.2.0_react@18.2.0 - dev: false - /redent/3.0.0: resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} engines: {node: '>=8'} @@ -15429,11 +15397,6 @@ packages: /tr46/0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - /transit-js/0.8.874: - resolution: {integrity: sha512-IDJJGKRzUbJHmN0P15HBBa05nbKor3r2MmG6aSt0UxXIlJZZKcddTk67/U7WyAeW9Hv/VYI02IqLzolsC4sbPA==} - engines: {node: '>= 0.10.0'} - dev: false - /traverse/0.6.6: resolution: {integrity: sha512-kdf4JKs8lbARxWdp7RKdNzoJBhGUcIalSYibuGyHJbmk40pOysQ0+QPvlkCOICOivDWU2IJo2rkrxyTK2AH4fw==} dev: true From 8d090a026a74698942f06d9f25da656e330b721b Mon Sep 17 00:00:00 2001 From: liulei Date: Sat, 21 Jan 2023 06:51:21 +0800 Subject: [PATCH 03/68] refactor(meta-vfs): map => record --- package.json | 1 - packages/asset-vfs/package.json | 12 +++ packages/asset-vfs/src/index.ts | 2 + .../components/CanvasDesignerOutlineTree.tsx | 6 +- .../components/CanvasDesignerPropsPanel.tsx | 2 +- .../indicatoir/DropIndicator.tsx | 4 +- .../indicatoir/SelectedIndicator.tsx | 2 +- .../indicatoir/SelectedToolBox.tsx | 2 +- .../src/hooks/usePageOutlineTree.tsx | 11 +-- .../src/hooks/useWidgetDrop.ts | 2 +- packages/meta-vfs/src/AppFile/index.ts | 94 +++++++++---------- packages/meta-vfs/src/AppManager/index.ts | 23 +++-- packages/meta-vfs/src/PageFile/index.ts | 12 +-- .../render/src/components/ReactRender.tsx | 8 +- .../src/components/ReactRenderTolerant.tsx | 3 +- .../render/src/components/WidgetVirtual.tsx | 13 ++- .../src/features/app/routers/mock.ts | 4 +- widgets/antd/src/ColWidget/index.tsx | 7 ++ 18 files changed, 117 insertions(+), 91 deletions(-) create mode 100644 packages/asset-vfs/package.json create mode 100644 packages/asset-vfs/src/index.ts diff --git a/package.json b/package.json index c07c7ee..82f18ed 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,6 @@ "@modou/widgets-antd": "workspace:^1.0.0", "@recoiljs/refine": "^0.1.1", "@vue/compiler-core": "^3.2.45", - "@vue/reactivity": "^3.2.45", "@vue/runtime-core": "^3.2.45", "ahooks": "^3.7.0", "antd": "^5.1.5", diff --git a/packages/asset-vfs/package.json b/packages/asset-vfs/package.json new file mode 100644 index 0000000..80fea0e --- /dev/null +++ b/packages/asset-vfs/package.json @@ -0,0 +1,12 @@ +{ + "name": "@modou/asset-vfs", + "version": "1.0.0", + "description": "", + "main": "src", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/packages/asset-vfs/src/index.ts b/packages/asset-vfs/src/index.ts new file mode 100644 index 0000000..23c6e31 --- /dev/null +++ b/packages/asset-vfs/src/index.ts @@ -0,0 +1,2 @@ +export const assetVFS = 'assetVFS' +// TODO render widgets setters diff --git a/packages/canvas-designer/src/components/CanvasDesignerOutlineTree.tsx b/packages/canvas-designer/src/components/CanvasDesignerOutlineTree.tsx index e202305..1dd36d0 100644 --- a/packages/canvas-designer/src/components/CanvasDesignerOutlineTree.tsx +++ b/packages/canvas-designer/src/components/CanvasDesignerOutlineTree.tsx @@ -81,9 +81,9 @@ const _CanvasDesignerOutlineTree: FC = () => { [WidgetBaseProps, string] >(dropNode.nodeType) .with('slot', () => [ - canvasDesignerFile.widgetMap.get( - (dropNode as unknown as OutlineTreeNodeSlot).slot.widgetId, - )?.meta!, + canvasDesignerFile.widgetMap[ + (dropNode as unknown as OutlineTreeNodeSlot).slot.widgetId + ]?.meta!, (dropNode as unknown as OutlineTreeNodeSlot).slot.path, ]) .with('widget', () => [ diff --git a/packages/canvas-designer/src/components/CanvasDesignerPropsPanel.tsx b/packages/canvas-designer/src/components/CanvasDesignerPropsPanel.tsx index 4f71453..c68ea94 100644 --- a/packages/canvas-designer/src/components/CanvasDesignerPropsPanel.tsx +++ b/packages/canvas-designer/src/components/CanvasDesignerPropsPanel.tsx @@ -23,7 +23,7 @@ import { useCanvasDesignerStore } from '../contexts/CanvasDesignerStoreContext' const useRenderFormItem = ({ widgetId }: { widgetId: string }) => { const { canvasDesignerFile } = useCanvasDesignerFile() - const widget = canvasDesignerFile.widgetMap.get(widgetId)! + const widget = canvasDesignerFile.widgetMap[widgetId] const widgetFactory = useContext(AppFactoryContext) const widgetMetadata = useMemo(() => { return widgetFactory.widgetByType[widget.meta.type].metadata diff --git a/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/DropIndicator.tsx b/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/DropIndicator.tsx index 3625f39..9225b24 100644 --- a/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/DropIndicator.tsx +++ b/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/DropIndicator.tsx @@ -193,8 +193,8 @@ const _DropIndicator: FC = () => { subtree: true, }) const dropElementsRendered = useMemo(() => { - return dropElements.filter(({ widgetId }) => - canvasDesignerFile.widgetMap.has(widgetId), + return dropElements.filter( + ({ widgetId }) => canvasDesignerFile.widgetMap[widgetId], ) }, [canvasDesignerFile.widgetMap, dropElements]) return ( diff --git a/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/SelectedIndicator.tsx b/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/SelectedIndicator.tsx index 7c6cccc..146801d 100644 --- a/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/SelectedIndicator.tsx +++ b/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/SelectedIndicator.tsx @@ -86,7 +86,7 @@ const _SelectIndicatorContent: FC = () => { display: display ? 'block' : 'none', } - const widget = appManager.widgetMap.get(selectedWidgetId)! + const widget = appManager.widgetMap[selectedWidgetId] // TODO 使用element const [{ isDragging }, drag, preview] = useDrag( () => ({ diff --git a/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/SelectedToolBox.tsx b/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/SelectedToolBox.tsx index 83416d9..5d85c9d 100644 --- a/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/SelectedToolBox.tsx +++ b/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/SelectedToolBox.tsx @@ -23,7 +23,7 @@ const _SelectedToolBox: FC = () => { const selectedWidgetId = canvasDesignerStore.selectedWidgetId const wrapperRef = useRef(null) - const widget = appManager.widgetMap.get(selectedWidgetId)! + const widget = appManager.widgetMap[selectedWidgetId] const [{ isDragging }, drag, preview] = useDrag( () => ({ type: widget.meta.type, diff --git a/packages/canvas-designer/src/hooks/usePageOutlineTree.tsx b/packages/canvas-designer/src/hooks/usePageOutlineTree.tsx index a70d686..d5cc1ee 100644 --- a/packages/canvas-designer/src/hooks/usePageOutlineTree.tsx +++ b/packages/canvas-designer/src/hooks/usePageOutlineTree.tsx @@ -33,9 +33,7 @@ export type OutlineTreeNode = DataNode & { export const usePageOutlineTree = () => { const { canvasDesignerFile } = useCanvasDesignerFile() const { appManager } = useAppManager() - const rootWidget = appManager.widgetMap.get( - canvasDesignerFile.meta.rootWidgetId, - )! + const rootWidget = appManager.widgetMap[canvasDesignerFile.meta.rootWidgetId] const appFactory = useContext(AppFactoryContext) const parentTreeNodes: OutlineTreeNode[] = [ @@ -84,14 +82,13 @@ export const usePageOutlineTree = () => { } const parentTreeNode = parentTreeNodes.pop() parentTreeNode?.children.unshift(curTreeNode) - const curSlot = appManager.widgetMap.get(curNode.widgetId)?.meta.slots?.[ - curNode.path - ] + const curSlot = + appManager.widgetMap[curNode.widgetId]?.meta.slots?.[curNode.path] if (curSlot && !isEmpty(curSlot)) { curSlot.forEach((widgetId: string) => { nodeStack.push({ _type: 'widget', - ...appManager.widgetMap.get(widgetId)?.meta!, + ...appManager.widgetMap[widgetId]?.meta!, }) parentTreeNodes.push(curTreeNode) }) diff --git a/packages/canvas-designer/src/hooks/useWidgetDrop.ts b/packages/canvas-designer/src/hooks/useWidgetDrop.ts index 00d34b0..2e3374c 100644 --- a/packages/canvas-designer/src/hooks/useWidgetDrop.ts +++ b/packages/canvas-designer/src/hooks/useWidgetDrop.ts @@ -124,7 +124,7 @@ export const useWidgetDrop = ({ // 普通组件只能放置兄弟节点 const dropType: DropType = slotPath ? DropType.Slot : DropType.Widget const widgetFactory = useContext(AppFactoryContext) - const widget = canvasDesignerFile.widgetMap.get(widgetId)! + const widget = canvasDesignerFile.widgetMap[widgetId]! const isEmptySlot = !!slotPath && isEmpty(widget.meta.slots[slotPath]) diff --git a/packages/meta-vfs/src/AppFile/index.ts b/packages/meta-vfs/src/AppFile/index.ts index 673a0f7..f78a221 100644 --- a/packages/meta-vfs/src/AppFile/index.ts +++ b/packages/meta-vfs/src/AppFile/index.ts @@ -1,4 +1,4 @@ -import { flatten, isArray, toPairs } from 'lodash' +import { isArray, keyBy } from 'lodash' import { action, @@ -24,12 +24,12 @@ export class AppFile extends BaseFile { super({ fileType: FileTypeEnum.App, meta, parentFile: null }) makeObservable(this, { subFileMap: observable, - entities: computed, - pages: computed, - entityMap: computed, - entityRelationMap: computed, - entityRelationsByTargetEntityNameMap: computed, - entityRelationsBySourceEntityNameMap: computed, + entities: computed.struct, + pages: computed.struct, + entityMap: computed.struct, + entityRelationMap: computed.struct, + entityRelationsByTargetEntityNameMap: computed.struct, + entityRelationsBySourceEntityNameMap: computed.struct, deleteEntity: action, deletePage: action, }) @@ -71,7 +71,7 @@ export class AppFile extends BaseFile { } get entityMap() { - return new Map(this.entities.map((entity) => [entity.meta.id, entity])) + return keyBy(this.entities, (entity) => entity.meta.id) } deleteEntity(entityId: string) { @@ -83,57 +83,49 @@ export class AppFile extends BaseFile { } get entityRelationMap() { - return new Map( - flatten( - this.entities.map((entity) => - entity.subFileMap.entityRelations.map((relation) => [ - relation.meta.id, - relation, - ]), + return this.entities.reduce>( + (pre, cur) => ({ + ...pre, + ...keyBy( + cur.subFileMap.entityRelations, + (relation) => relation.meta.id, ), - ), + }), + {}, ) } get entityRelationsByTargetEntityNameMap() { - return new Map( - toPairs( - [...this.entityRelationMap.values()].reduce< - Record - >((pre, cur) => { - // TODO 如果是ManyToOne 的 Lookup 则不在对方双向生成关系 - // if ( - // cur.type === EntityRelationTypeEnum.Lookup && - // cur.relationType === EntityRelationLookupRelationTypeEnum.ManyToOne - // ) { - // return pre - // } - const targetEntityName = cur.meta.targetEntity - if (!isArray(pre[targetEntityName])) { - pre[targetEntityName] = [] - } - pre[targetEntityName].push(cur) - return pre - }, {}), - ), - ) + return Object.values(this.entityRelationMap).reduce< + Record + >((pre, cur) => { + // TODO 如果是ManyToOne 的 Lookup 则不在对方双向生成关系 + // if ( + // cur.type === EntityRelationTypeEnum.Lookup && + // cur.relationType === EntityRelationLookupRelationTypeEnum.ManyToOne + // ) { + // return pre + // } + const targetEntityName = cur.meta.targetEntity + if (!isArray(pre[targetEntityName])) { + pre[targetEntityName] = [] + } + pre[targetEntityName].push(cur) + return pre + }, {}) } get entityRelationsBySourceEntityNameMap() { - return new Map( - toPairs( - [...this.entityRelationMap.values()].reduce< - Record - >((pre, cur) => { - const sourceEntityName = cur.meta.sourceEntity - if (!isArray(pre[sourceEntityName])) { - pre[sourceEntityName] = [] - } - pre[sourceEntityName].push(cur) - return pre - }, {}), - ), - ) + return Object.values(this.entityRelationMap).reduce< + Record + >((pre, cur) => { + const sourceEntityName = cur.meta.sourceEntity + if (!isArray(pre[sourceEntityName])) { + pre[sourceEntityName] = [] + } + pre[sourceEntityName].push(cur) + return pre + }, {}) } toJSON() { diff --git a/packages/meta-vfs/src/AppManager/index.ts b/packages/meta-vfs/src/AppManager/index.ts index 0729d5a..a2a4074 100644 --- a/packages/meta-vfs/src/AppManager/index.ts +++ b/packages/meta-vfs/src/AppManager/index.ts @@ -1,13 +1,22 @@ import { flatten } from 'lodash' -import { makeAutoObservable } from '@modou/reactivity' +import { computed, makeObservable } from '@modou/reactivity' import { AppFile } from '../AppFile' +import { WidgetFile } from '../WidgetFile' export class AppManager { constructor(appFile: AppFile) { this.root = appFile - makeAutoObservable(this) + makeObservable(this, { + // root: observable, + app: computed, + pageMap: computed.struct, + entityMap: computed.struct, + widgetMap: computed.struct, + entityFieldMap: computed.struct, + entityRelationMap: computed.struct, + }) } private readonly root: AppFile @@ -26,13 +35,9 @@ export class AppManager { get widgetMap() { // TODO 优化 直接从page.widgetMap 取值 - return new Map( - flatten( - this.app.pages.map((page) => - page.subFileMap.widgets.map((widget) => [widget.meta.id, widget]), - ), - ), - ) + return this.app.pages.reduce>((pre, cur) => { + return { ...pre, ...cur.widgetMap } + }, {}) } get entityFieldMap() { diff --git a/packages/meta-vfs/src/PageFile/index.ts b/packages/meta-vfs/src/PageFile/index.ts index f2e6191..71a8249 100644 --- a/packages/meta-vfs/src/PageFile/index.ts +++ b/packages/meta-vfs/src/PageFile/index.ts @@ -1,5 +1,5 @@ import produce from 'immer' -import { isEmpty, isFunction, isObject, omit } from 'lodash' +import { isEmpty, isFunction, isObject, keyBy, omit } from 'lodash' import { WidgetBaseProps } from '@modou/core' import { @@ -37,8 +37,8 @@ export class PageFile extends BaseFile { makeObservable(this, { subFileMap: observable, widgets: computed, - widgetMap: computed, - widgetRelationById: computed, + widgetMap: computed.struct, + widgetRelationById: computed.struct, addWidget: action, deleteWidget: action, updateWidgets: action, @@ -55,7 +55,7 @@ export class PageFile extends BaseFile { } get widgetMap() { - return new Map(this.widgets.map((widget) => [widget.meta.id, widget])) + return keyBy(this.subFileMap.widgets, (widget) => widget.meta.id) } get widgetRelationById(): WidgetRelationById { @@ -73,7 +73,7 @@ export class PageFile extends BaseFile { slotChildren.forEach((widgetId) => { if (!Reflect.has(pre, widgetId)) { pre[widgetId] = { - props: this.widgetMap.get(widgetId)?.meta!, + props: this.widgetMap[widgetId].meta, parent, slotPath, } @@ -100,7 +100,7 @@ export class PageFile extends BaseFile { targetSlotPath: string }) { const sourceWidget = WidgetFile.create(sourceWidgetMeta, this) - const targetWidget = this.widgetMap.get(targetWidgetId) + const targetWidget = this.widgetMap[targetWidgetId] if (!targetWidget) { return } diff --git a/packages/render/src/components/ReactRender.tsx b/packages/render/src/components/ReactRender.tsx index 6c42c72..09ac2ce 100644 --- a/packages/render/src/components/ReactRender.tsx +++ b/packages/render/src/components/ReactRender.tsx @@ -4,6 +4,7 @@ import { FC, useContext } from 'react' import * as React from 'react' import { AppFactoryContext, AppManagerProvider } from '@modou/core' +import { observer } from '@modou/reactivity-react' import { StateManagerProvider } from '@modou/state-manager/src/contexts' import { CanvasFileContextProvider } from '../contexts' @@ -12,14 +13,15 @@ import { MoDouRenderProps } from '../types' import { ReactRenderTolerant } from './ReactRenderTolerant' // TODO 支持页面的 State 缓存 比如详情页面回退到列表页面 -export const ReactRender: FC = (props) => { +const _ReactRender: FC = (props) => { const appFactory = useContext(AppFactoryContext) const { file, appManager } = useInitRender() const { stateManager } = useInitStateManager({ app: appManager?.app, file }) - console.log('stateManager', file, appManager, stateManager) if (!file || !appManager || !stateManager) { return null } + console.log('stateManager', file.widgetMap, appManager, stateManager) + return ( {/* TODO 去除点(.)保持跟其他Context统一 */} @@ -35,3 +37,5 @@ export const ReactRender: FC = (props) => { ) } + +export const ReactRender = observer(_ReactRender) diff --git a/packages/render/src/components/ReactRenderTolerant.tsx b/packages/render/src/components/ReactRenderTolerant.tsx index 0683e4a..72a5b34 100644 --- a/packages/render/src/components/ReactRenderTolerant.tsx +++ b/packages/render/src/components/ReactRenderTolerant.tsx @@ -4,6 +4,7 @@ import * as React from 'react' import { useAppManager } from '@modou/core' import { mcss } from '@modou/css-in-js' +import { trace } from '@modou/reactivity' import { observer } from '@modou/reactivity-react' import { useCanvasFile } from '../contexts' @@ -14,7 +15,7 @@ const _ReactRenderTolerant: FC = ({ host = 'browser' }) => { const { canvasFile } = useCanvasFile() const { appManager } = useAppManager() // FIXME 判断当前所在环境 是否从props更新widgets 可以加一个 host - const rootWidget = appManager.widgetMap.get(canvasFile.meta.rootWidgetId) + const rootWidget = appManager.widgetMap[canvasFile.meta.rootWidgetId] return rootWidget ? ( ) : ( diff --git a/packages/render/src/components/WidgetVirtual.tsx b/packages/render/src/components/WidgetVirtual.tsx index 1e12ead..f3f1748 100644 --- a/packages/render/src/components/WidgetVirtual.tsx +++ b/packages/render/src/components/WidgetVirtual.tsx @@ -27,9 +27,10 @@ import { evalExpression, isExpression } from '../utils/evaluate' const _WidgetVirtual: FC<{ widgetId: string }> = ({ widgetId }) => { + // trace(true) const { appManager } = useAppManager() const { canvasState } = useStateManager() - const widget = appManager.widgetMap.get(widgetId)! + const widget = appManager.widgetMap[widgetId] const appFactory = useContext(AppFactoryContext) let widgetState = canvasState.subState.widget[widget.meta.id] if (!widgetState) { @@ -110,7 +111,14 @@ const _WidgetVirtual: FC<{ ) }) } else { - set(widgetState.state, `${path}`, rawPropVal) + console.log('fullPath', fullPath, rawPropVal) + set( + widgetState.state, + `${fullPath}`, + rawPropVal === undefined + ? get(widgetState.state, fullPath) + : rawPropVal, + ) } }) }) @@ -118,7 +126,6 @@ const _WidgetVirtual: FC<{ // FIXME 会导致重新渲染 // FIXME 完善组件类型 - // console.log('toJS(widgetState)', toJS(widgetState.state)) return ( > = ({ useEffect(() => { console.log('我是Col 我重新渲染了', instance.widgetId) }) + useWhyDidYouUpdate('ASDASDASDASD', [ + span, + instance, + renderSlots, + renderSlotPaths, + ]) return ( Date: Sat, 21 Jan 2023 14:06:42 +0800 Subject: [PATCH 04/68] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96=E8=84=9A?= =?UTF-8?q?=E6=9C=AC=E6=89=A7=E8=A1=8C=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + .../indicatoir/SelectedToolBox.tsx | 2 - packages/evaluate/package.json | 12 ++ packages/evaluate/src/index.ts | 5 + packages/meta-vfs/src/WidgetFile/index.ts | 99 +++++++++++++++- packages/reactivity/src/index.ts | 1 + .../render/src/components/ReactRender.tsx | 5 +- .../render/src/components/WidgetVirtual.tsx | 106 +++++++----------- packages/render/src/utils/evaluate.ts | 8 +- pnpm-lock.yaml | 4 +- .../src/features/app/routers/mock.ts | 9 +- .../src/features/page/routers/Page.tsx | 2 +- widgets/antd/src/ColWidget/index.tsx | 7 -- 13 files changed, 174 insertions(+), 87 deletions(-) create mode 100644 packages/evaluate/package.json create mode 100644 packages/evaluate/src/index.ts diff --git a/package.json b/package.json index 82f18ed..864d885 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "@modou/compile-core": "workspace:^0.0.1", "@modou/core": "workspace:^1.0.0", "@modou/css-in-js": "workspace:^1.0.0", + "@modou/evaluate": "workspace:^1.0.0", "@modou/meta-vfs": "workspace:^0.0.1", "@modou/reactivity": "workspace:^0.0.1", "@modou/reactivity-react": "workspace:^0.0.1", diff --git a/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/SelectedToolBox.tsx b/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/SelectedToolBox.tsx index 5d85c9d..b02871e 100644 --- a/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/SelectedToolBox.tsx +++ b/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/SelectedToolBox.tsx @@ -19,8 +19,6 @@ const _SelectedToolBox: FC = () => { const { canvasDesignerFile } = useCanvasDesignerFile() const { widgetRelationById } = canvasDesignerFile - console.log('widgetRelationById', widgetRelationById) - const selectedWidgetId = canvasDesignerStore.selectedWidgetId const wrapperRef = useRef(null) const widget = appManager.widgetMap[selectedWidgetId] diff --git a/packages/evaluate/package.json b/packages/evaluate/package.json new file mode 100644 index 0000000..78ecb93 --- /dev/null +++ b/packages/evaluate/package.json @@ -0,0 +1,12 @@ +{ + "name": "@modou/evaluate", + "version": "1.0.0", + "description": "", + "main": "src", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/packages/evaluate/src/index.ts b/packages/evaluate/src/index.ts new file mode 100644 index 0000000..b30a0ed --- /dev/null +++ b/packages/evaluate/src/index.ts @@ -0,0 +1,5 @@ +const EXPRESSION_REG = /[\s\S]*{{[\s\S]*}}[\s\S]*/m + +export const isExpression = (str: unknown): str is string => { + return typeof str === 'string' && EXPRESSION_REG.test(str) +} diff --git a/packages/meta-vfs/src/WidgetFile/index.ts b/packages/meta-vfs/src/WidgetFile/index.ts index ab324d4..8e57171 100644 --- a/packages/meta-vfs/src/WidgetFile/index.ts +++ b/packages/meta-vfs/src/WidgetFile/index.ts @@ -1,21 +1,116 @@ -import { omit } from 'lodash' +import { + InterpolationNode, + SimpleExpressionNode, + TextNode, + baseParse, +} from '@vue/compiler-core' +import { mapValues, omit } from 'lodash' import { WidgetBaseProps } from '@modou/core' -import { makeObservable, observable, runInAction } from '@modou/reactivity' +import { isExpression } from '@modou/evaluate' +import { + computed, + makeObservable, + observable, + runInAction, +} from '@modou/reactivity' +import { ParseNodeTypes } from '@modou/render/src/types' import { BaseFile, BaseFileMete } from '../BaseFile' import { PageFile } from '../PageFile' import { FileTypeEnum } from '../types' +type MetaPath = string + +enum MetaDepTypeEnum { + Widget, +} + +// interface MetaDep { +// type: MetaDepTypeEnum +// path: string +// } +interface MetaValExpression { + type: 'Expression' + raw: string + ast: ReturnType + evalString: string +} + +interface MetaValNormal { + type: 'Normal' + raw: any +} +type MetaVal = MetaValExpression | MetaValNormal + export type WidgetFileMeta = BaseFileMete + export class WidgetFile extends BaseFile<{}, WidgetFileMeta, PageFile> { protected constructor(meta: WidgetFileMeta, parentFile: PageFile) { super({ fileType: FileTypeEnum.Widget, meta, parentFile }) makeObservable(this, { subFileMap: observable, + // depMap: computed.struct, + flattenedMetaValMap: computed.struct, }) } + get flattenedMetaValMap(): Record { + return mapValues( + this.meta.props, + (value) => { + if (isExpression(value)) { + const ast = baseParse(value) + return { + type: 'Expression', + raw: value, + ast, + evalString: `\`${ast.children + .map((item) => { + // @ts-expect-error + if (item.type === ParseNodeTypes.TEXT) { + return (item as unknown as TextNode).content + // @ts-expect-error + } else if (item.type === ParseNodeTypes.INTERPOLATION) { + const content = ( + (item as unknown as InterpolationNode) + .content as unknown as SimpleExpressionNode + ).content + if (content) { + return `\${${content}}` + } + return '' + } + // TODO 适配其他类型 + return item.loc.source + }) + .join('')}\``, + } + } else { + return { + type: 'Normal', + raw: value, + } + } + }, + ) + } + + // TODO state 修改为主动 watch dep + // 按钮-{{colDSL.span}} + // get depMap(): Record { + // return mapValues( + // pickBy( + // flatten, Record>(this.meta.props), + // (value) => isExpression(value), + // ), + // (value) => ({ + // type: MetaDepTypeEnum.Widget, + // path: value, + // }), + // ) + // } + subFileMap = {} toJSON() { diff --git a/packages/reactivity/src/index.ts b/packages/reactivity/src/index.ts index b79ab24..5c1dbcc 100644 --- a/packages/reactivity/src/index.ts +++ b/packages/reactivity/src/index.ts @@ -18,6 +18,7 @@ export const makeAutoObservable = mobx.makeAutoObservable export const makeObservable = mobx.makeObservable export const observable = mobx.observable export const observe = mobx.observe +export const reaction = mobx.reaction export const runInAction = mobx.runInAction export const set = mobx.set export const toJS = mobx.toJS diff --git a/packages/render/src/components/ReactRender.tsx b/packages/render/src/components/ReactRender.tsx index 09ac2ce..2b02c45 100644 --- a/packages/render/src/components/ReactRender.tsx +++ b/packages/render/src/components/ReactRender.tsx @@ -1,6 +1,6 @@ import { ConfigProvider } from 'antd' import zhCN from 'antd/locale/zh_CN' -import { FC, useContext } from 'react' +import { FC, useContext, useEffect } from 'react' import * as React from 'react' import { AppFactoryContext, AppManagerProvider } from '@modou/core' @@ -17,11 +17,10 @@ const _ReactRender: FC = (props) => { const appFactory = useContext(AppFactoryContext) const { file, appManager } = useInitRender() const { stateManager } = useInitStateManager({ app: appManager?.app, file }) + if (!file || !appManager || !stateManager) { return null } - console.log('stateManager', file.widgetMap, appManager, stateManager) - return ( {/* TODO 去除点(.)保持跟其他Context统一 */} diff --git a/packages/render/src/components/WidgetVirtual.tsx b/packages/render/src/components/WidgetVirtual.tsx index f3f1748..bb5caba 100644 --- a/packages/render/src/components/WidgetVirtual.tsx +++ b/packages/render/src/components/WidgetVirtual.tsx @@ -1,19 +1,12 @@ -import { - InterpolationNode, - SimpleExpressionNode, - TextNode, - baseParse, -} from '@vue/compiler-core' -import { useMount } from 'ahooks' -import { flatten } from 'flat' -import { get, keys, set } from 'lodash' -import { FC, useContext, useRef } from 'react' +import { mapValues, set } from 'lodash' +import { FC, useContext, useEffect } from 'react' import * as React from 'react' import { AppFactoryContext, useAppManager } from '@modou/core' import { IReactionDisposer, autorun, + reaction, runInAction, toJS, } from '@modou/reactivity' @@ -21,13 +14,13 @@ import { observer, useLocalObservable } from '@modou/reactivity-react' import { WidgetState } from '@modou/state-manager' import { useStateManager } from '@modou/state-manager/src/contexts' -import { ParseNodeTypes } from '../types' -import { evalExpression, isExpression } from '../utils/evaluate' +import { evalExpression } from '../utils/evaluate' const _WidgetVirtual: FC<{ widgetId: string }> = ({ widgetId }) => { // trace(true) + // 按钮-{{colDSL.span}} const { appManager } = useAppManager() const { canvasState } = useStateManager() const widget = appManager.widgetMap[widgetId] @@ -40,8 +33,7 @@ const _WidgetVirtual: FC<{ const widgetDef = appFactory.widgetByType[widget.meta.type] // TODO any 替换 state 定义 const WidgetComponent = widgetDef.component - - const state = useLocalObservable(() => ({ + const localState = useLocalObservable(() => ({ get renderSlots() { return Object.entries(widgetDef.metadata.slots || {}) .map(([slotPath, slot]) => { @@ -70,59 +62,37 @@ const _WidgetVirtual: FC<{ }, })) - const watchStopsRef = useRef>({}) - - useMount(() => { - const flattenStateKeys = keys(flatten(widgetState.state)) - flattenStateKeys.forEach((path) => { - if (Reflect.has(watchStopsRef.current, path)) { - return - } - watchStopsRef.current[path] = autorun(() => { - const fullPath = `${path}` - const rawPropVal = get(widget.meta.props, fullPath) - if (isExpression(rawPropVal)) { - const ast = baseParse(rawPropVal) - const expression = `\`${ast.children - .map((item) => { - // @ts-expect-error - if (item.type === ParseNodeTypes.TEXT) { - return (item as unknown as TextNode).content - // @ts-expect-error - } else if (item.type === ParseNodeTypes.INTERPOLATION) { - const content = ( - (item as unknown as InterpolationNode) - .content as unknown as SimpleExpressionNode - ).content - if (content) { - return `\${${content}}` - } - return '' - } - // TODO 适配其他类型 - return item.loc.source - }) - .join('')}\`` - runInAction(() => { - set( - widgetState.state, - fullPath, - evalExpression(expression, canvasState), + useEffect(() => { + const stopExps: IReactionDisposer[] = [] + const stop = reaction( + () => widgetState.file.flattenedMetaValMap, + (value, prev) => { + stopExps.forEach((stop) => stop()) + Object.entries(value).forEach(([path, val]) => { + if (val.type === 'Normal') { + if (prev?.[path]?.raw !== val.raw) { + set(widgetState.state, path, val.raw) + } + } else { + stopExps.push( + autorun(() => { + const newVal = evalExpression(val.evalString, canvasState) + runInAction(() => { + set(widgetState.state, path, newVal) + }) + }), ) - }) - } else { - console.log('fullPath', fullPath, rawPropVal) - set( - widgetState.state, - `${fullPath}`, - rawPropVal === undefined - ? get(widgetState.state, fullPath) - : rawPropVal, - ) - } - }) - }) - }) + } + }) + }, + { + fireImmediately: true, + }, + ) + return () => { + stop() + } + }, []) // FIXME 会导致重新渲染 // FIXME 完善组件类型 @@ -130,8 +100,8 @@ const _WidgetVirtual: FC<{ ) } diff --git a/packages/render/src/utils/evaluate.ts b/packages/render/src/utils/evaluate.ts index 6277bce..b1e07a7 100644 --- a/packages/render/src/utils/evaluate.ts +++ b/packages/render/src/utils/evaluate.ts @@ -1,3 +1,5 @@ +import { mapValues } from 'lodash' + import { PageState } from '@modou/state-manager' const EXPRESSION_REG = /[\s\S]*{{[\s\S]*}}[\s\S]*/m @@ -14,7 +16,11 @@ export const evalExpression = (expression: string, canvasState: PageState) => { `with(state){ return ${expression} }`, - ).call(null, canvasState.subState.widget) + // TODO state 打平收集到 stateManager + ).call( + null, + mapValues(canvasState.subState.widget, (widget) => widget.state), + ) } catch (e) { return String((e as SyntaxError)?.message) ?? 'Error' } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9ec0c76..96dd584 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,6 +15,7 @@ importers: '@modou/compile-core': workspace:^0.0.1 '@modou/core': workspace:^1.0.0 '@modou/css-in-js': workspace:^1.0.0 + '@modou/evaluate': workspace:^1.0.0 '@modou/meta-vfs': workspace:^0.0.1 '@modou/reactivity': workspace:^0.0.1 '@modou/reactivity-react': workspace:^0.0.1 @@ -31,7 +32,6 @@ importers: '@types/react-dom': ^18.0.6 '@vitejs/plugin-react': ^3.0.1 '@vue/compiler-core': ^3.2.45 - '@vue/reactivity': ^3.2.45 '@vue/runtime-core': ^3.2.45 ahooks: ^3.7.0 antd: ^5.1.5 @@ -72,6 +72,7 @@ importers: '@modou/compile-core': link:packages/compiler-core '@modou/core': link:packages/core '@modou/css-in-js': link:packages/css-in-js + '@modou/evaluate': link:packages/evaluate '@modou/meta-vfs': link:packages/meta-vfs '@modou/reactivity': link:packages/reactivity '@modou/reactivity-react': link:packages/reactivity-react @@ -82,7 +83,6 @@ importers: '@modou/widgets-antd': link:widgets/antd '@recoiljs/refine': 0.1.1 '@vue/compiler-core': 3.2.45 - '@vue/reactivity': 3.2.45 '@vue/runtime-core': 3.2.45 ahooks: 3.7.1_react@18.2.0 antd: 5.1.5_biqbaboplfbrettd7655fr4n2y diff --git a/websites/workspace/src/features/app/routers/mock.ts b/websites/workspace/src/features/app/routers/mock.ts index 61f0d9f..c5abe32 100644 --- a/websites/workspace/src/features/app/routers/mock.ts +++ b/websites/workspace/src/features/app/routers/mock.ts @@ -29,8 +29,15 @@ export const mock_appFile = AppFile.create({ // mock app end // mock page start +const defaultButton = WidgetMetadata.mrSchemeToDefaultJson( + buttonWidgetMetadata.jsonPropsSchema, +) const buttonDSL: WidgetBaseProps = { - ...WidgetMetadata.mrSchemeToDefaultJson(buttonWidgetMetadata.jsonPropsSchema), + ...defaultButton, + props: { + ...defaultButton.props, + title: '按钮-{{colDSL.span}}-大漠孤烟直哈哈', + }, id: 'buttonDSL', } diff --git a/websites/workspace/src/features/page/routers/Page.tsx b/websites/workspace/src/features/page/routers/Page.tsx index 361c5cc..8e6a941 100644 --- a/websites/workspace/src/features/page/routers/Page.tsx +++ b/websites/workspace/src/features/page/routers/Page.tsx @@ -3,7 +3,7 @@ import { PageRouterParamsKey } from '@/types' import { generateRouterPath } from '@/utils/router' import { Col, Row } from 'antd' import { head } from 'lodash' -import { FC, useLayoutEffect } from 'react' +import { FC, useEffect, useLayoutEffect } from 'react' import { useNavigate, useParams } from 'react-router-dom' import { CanvasDesigner } from '@modou/canvas-designer' diff --git a/widgets/antd/src/ColWidget/index.tsx b/widgets/antd/src/ColWidget/index.tsx index f884a68..5f355da 100644 --- a/widgets/antd/src/ColWidget/index.tsx +++ b/widgets/antd/src/ColWidget/index.tsx @@ -1,4 +1,3 @@ -import { useWhyDidYouUpdate } from 'ahooks' import { Col } from 'antd' import { FC, useEffect } from 'react' @@ -14,12 +13,6 @@ export const ColWidget: FC> = ({ useEffect(() => { console.log('我是Col 我重新渲染了', instance.widgetId) }) - useWhyDidYouUpdate('ASDASDASDASD', [ - span, - instance, - renderSlots, - renderSlotPaths, - ]) return ( Date: Sat, 21 Jan 2023 14:25:20 +0800 Subject: [PATCH 05/68] =?UTF-8?q?feat(designer):=20=E7=9B=91=E5=90=ACele?= =?UTF-8?q?=E5=B1=9E=E6=80=A7=E5=8F=98=E5=8C=96=E5=8A=A8=E6=80=81=E6=94=B9?= =?UTF-8?q?=E5=8F=98=E8=BE=85=E5=8A=A9=E7=BC=96=E8=BE=91=E6=A1=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../indicatoir/SelectedIndicator.tsx | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/SelectedIndicator.tsx b/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/SelectedIndicator.tsx index 146801d..554cc4d 100644 --- a/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/SelectedIndicator.tsx +++ b/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/SelectedIndicator.tsx @@ -1,3 +1,4 @@ +import { useMemoizedFn, useMutationObserver } from 'ahooks' import { CSSProperties, FC, @@ -38,17 +39,24 @@ const _SelectIndicatorContent: FC = () => { }) const [display, setDisplay] = useState(false) const [styleUpdater, setStyleUpdater] = useState(0) + const simulatorInstance = useContext(SimulatorInstanceContext) + + const forceUpdateStyle = useMemoizedFn(() => { + setStyleUpdater((prevState) => prevState + 1) + }) // TODO 是否使用 watch deep useEffect(() => { // void Promise.resolve().then(() => { // setStyleUpdater((prevState) => prevState + 1) // }) - setTimeout(() => { - setStyleUpdater((prevState) => prevState + 1) - }) - }, [canvasDesignerFile.widgets]) - const simulatorInstance = useContext(SimulatorInstanceContext) + setTimeout(forceUpdateStyle) + }, [canvasDesignerFile.widgets, forceUpdateStyle]) + useMutationObserver(forceUpdateStyle, simulatorInstance.document?.body, { + childList: true, + subtree: true, + attributes: true, + }) useEffect(() => { if (!selectedWidgetId) { setDisplay(false) From ff3effe9e76c617f131e6db15630cdec49858e65 Mon Sep 17 00:00:00 2001 From: liulei Date: Sat, 21 Jan 2023 16:13:07 +0800 Subject: [PATCH 06/68] fix: ts type --- packages/meta-vfs/README.md | 6 +++--- packages/meta-vfs/docs/index.md | 2 +- packages/meta-vfs/src/BaseFile/index.ts | 2 +- packages/meta-vfs/src/Foo/index.tsx | 4 ---- packages/meta-vfs/tsconfig.json | 4 ++-- packages/reactivity-react/src/observer.ts | 11 ++++++++--- ...eactionCleanupTrackingUsingFinalizationRegister.ts | 4 ++-- .../utils/createTimerBasedReactionCleanupTracking.ts | 4 ++-- .../reactivity-react/src/utils/printDebugValue.ts | 4 ++-- .../src/utils/reactionCleanupTrackingCommon.ts | 8 ++++---- packages/reactivity/src/index.ts | 11 ++++++++++- packages/setters/src/components/string.tsx | 2 +- .../src/features/app/components/ModuleManagerPage.tsx | 8 ++++---- .../src/features/entity/components/EntitiesER.tsx | 7 +++---- .../features/entity/components/EntityFieldCreator.tsx | 4 ++-- .../src/features/entity/components/EntityFields.tsx | 2 +- .../src/features/entity/hooks/useEntityCreator.ts | 2 +- .../workspace/src/features/entity/routers/Entity.tsx | 2 +- widgets/antd/src/ButtonWidget/constants.ts | 2 +- 19 files changed, 49 insertions(+), 40 deletions(-) diff --git a/packages/meta-vfs/README.md b/packages/meta-vfs/README.md index e767825..32ab99e 100644 --- a/packages/meta-vfs/README.md +++ b/packages/meta-vfs/README.md @@ -1,9 +1,9 @@ -# @modou/file +# @modou/meta-vfs ## TODO 增加单元测试 -[![NPM version](https://img.shields.io/npm/v/@modou/file.svg?style=flat)](https://npmjs.org/package/@modou/file) -[![NPM downloads](http://img.shields.io/npm/dm/@modou/file.svg?style=flat)](https://npmjs.org/package/@modou/file) +[![NPM version](https://img.shields.io/npm/v/@modou/meta-vfs.svg?style=flat)](https://npmjs.org/package/@modou/meta-vfs) +[![NPM downloads](http://img.shields.io/npm/dm/@modou/meta-vfs.svg?style=flat)](https://npmjs.org/package/@modou/meta-vfs) diff --git a/packages/meta-vfs/docs/index.md b/packages/meta-vfs/docs/index.md index f3d82e1..8eedcdc 100644 --- a/packages/meta-vfs/docs/index.md +++ b/packages/meta-vfs/docs/index.md @@ -19,4 +19,4 @@ features: description: Put ! description here --- -@modou/file +@modou/meta-vfs diff --git a/packages/meta-vfs/src/BaseFile/index.ts b/packages/meta-vfs/src/BaseFile/index.ts index 3faa66a..080ed2d 100644 --- a/packages/meta-vfs/src/BaseFile/index.ts +++ b/packages/meta-vfs/src/BaseFile/index.ts @@ -1,7 +1,7 @@ import { isFunction, mapValues } from 'lodash' import { MDVersion } from '@modou/core' -import { FileTypeEnum, UpdateParams } from '@modou/file' +import { FileTypeEnum, UpdateParams } from '@modou/meta-vfs' import { action, makeObservable, observable } from '@modou/reactivity' export type BaseFileMete = { diff --git a/packages/meta-vfs/src/Foo/index.tsx b/packages/meta-vfs/src/Foo/index.tsx index 4f980bb..133ad48 100644 --- a/packages/meta-vfs/src/Foo/index.tsx +++ b/packages/meta-vfs/src/Foo/index.tsx @@ -18,7 +18,6 @@ runInAction(() => { const page1 = PageFile.create( { name: 'Page_Demo_1', - version: '0.0.0', id: generateId(), rootWidgetId: '0', }, @@ -27,7 +26,6 @@ runInAction(() => { const page2 = PageFile.create( { name: 'Page_Demo_2', - version: '0.0.0', id: generateId(), rootWidgetId: '0', }, @@ -37,7 +35,6 @@ runInAction(() => { WidgetFile.create( { name: '按钮_1', - version: '0.0.0', id: generateId(), slots: {}, props: { @@ -50,7 +47,6 @@ runInAction(() => { WidgetFile.create( { name: '输入框_2', - version: '0.0.0', id: generateId(), slots: {}, props: { diff --git a/packages/meta-vfs/tsconfig.json b/packages/meta-vfs/tsconfig.json index 7f78f05..da4f821 100644 --- a/packages/meta-vfs/tsconfig.json +++ b/packages/meta-vfs/tsconfig.json @@ -12,8 +12,8 @@ "baseUrl": "./", "paths": { "@@/*": [".dumi/tmp/*"], - "@modou/file": ["src"], - "@modou/file/*": ["src/*", "*"] + "@modou/meta-vfs": ["src"], + "@modou/meta-vfs/*": ["src/*", "*"] }, }, "include": [".dumi/**/*", ".dumirc.ts", "src/**/*"] diff --git a/packages/reactivity-react/src/observer.ts b/packages/reactivity-react/src/observer.ts index 0bbdf56..5f636fa 100644 --- a/packages/reactivity-react/src/observer.ts +++ b/packages/reactivity-react/src/observer.ts @@ -83,12 +83,15 @@ export function observer

( ) } - if (ReactMemoSymbol && baseComponent['$$typeof'] === ReactMemoSymbol) { + // @ts-expect-error + if (ReactMemoSymbol && baseComponent.$$typeof === ReactMemoSymbol) { throw new Error( - `[mobx-react-lite] You are trying to use \`observer\` on a function component wrapped in either another \`observer\` or \`React.memo\`. The observer already applies 'React.memo' for you.`, + `[mobx-react-lite] You are trying to use \`observer\` on a function component` + + ` wrapped in either another \`observer\` or \`React.memo\`. The observer already applies 'React.memo' for you.`, ) } - // The working of observer is explained step by step in this talk: https://www.youtube.com/watch?v=cPF4iBedoF0&feature=youtu.be&t=1307 + // The working of observer is explained step by step in this talk: + // https://www.youtube.com/watch?v=cPF4iBedoF0&feature=youtu.be&t=1307 if (isUsingStaticRendering()) { return baseComponent } @@ -102,9 +105,11 @@ export function observer

( // so we can patch render and apply memo if ( ReactForwardRefSymbol && + // @ts-expect-error baseComponent['$$typeof'] === ReactForwardRefSymbol ) { useForwardRef = true + // @ts-expect-error render = baseComponent['render'] if (typeof render !== 'function') { throw new Error( diff --git a/packages/reactivity-react/src/utils/createReactionCleanupTrackingUsingFinalizationRegister.ts b/packages/reactivity-react/src/utils/createReactionCleanupTrackingUsingFinalizationRegister.ts index 89b8f87..c808ae0 100644 --- a/packages/reactivity-react/src/utils/createReactionCleanupTrackingUsingFinalizationRegister.ts +++ b/packages/reactivity-react/src/utils/createReactionCleanupTrackingUsingFinalizationRegister.ts @@ -1,4 +1,4 @@ -import { Reaction } from '@modou/reactivity' +import { ReactionType } from '@modou/reactivity' import { FinalizationRegistry as FinalizationRegistryMaybeUndefined } from './FinalizationRegistryWrapper' import { @@ -29,7 +29,7 @@ export function createReactionCleanupTrackingUsingFinalizationRegister( return { addReactionToTrack( reactionTrackingRef: React.MutableRefObject, - reaction: Reaction, + reaction: ReactionType, objectRetainedByReact: object, ) { const token = globalCleanupTokensCounter++ diff --git a/packages/reactivity-react/src/utils/createTimerBasedReactionCleanupTracking.ts b/packages/reactivity-react/src/utils/createTimerBasedReactionCleanupTracking.ts index e51c341..5c27604 100644 --- a/packages/reactivity-react/src/utils/createTimerBasedReactionCleanupTracking.ts +++ b/packages/reactivity-react/src/utils/createTimerBasedReactionCleanupTracking.ts @@ -1,4 +1,4 @@ -import { Reaction } from '@modou/reactivity' +import { ReactionType } from '@modou/reactivity' import { CLEANUP_TIMER_LOOP_MILLIS, @@ -110,7 +110,7 @@ export function createTimerBasedReactionCleanupTracking(): ReactionCleanupTracki return { addReactionToTrack( reactionTrackingRef: React.MutableRefObject, - reaction: Reaction, + reaction: ReactionType, /** * On timer based implementation we don't really need this object, * but we keep the same api diff --git a/packages/reactivity-react/src/utils/printDebugValue.ts b/packages/reactivity-react/src/utils/printDebugValue.ts index 1dc0afa..3ff7bcf 100644 --- a/packages/reactivity-react/src/utils/printDebugValue.ts +++ b/packages/reactivity-react/src/utils/printDebugValue.ts @@ -1,5 +1,5 @@ -import { Reaction, getDependencyTree } from '@modou/reactivity' +import { ReactionType, getDependencyTree } from '@modou/reactivity' -export function printDebugValue(v: Reaction) { +export function printDebugValue(v: ReactionType) { return getDependencyTree(v) } diff --git a/packages/reactivity-react/src/utils/reactionCleanupTrackingCommon.ts b/packages/reactivity-react/src/utils/reactionCleanupTrackingCommon.ts index dde7154..06c0c43 100644 --- a/packages/reactivity-react/src/utils/reactionCleanupTrackingCommon.ts +++ b/packages/reactivity-react/src/utils/reactionCleanupTrackingCommon.ts @@ -1,6 +1,6 @@ -import { Reaction } from '@modou/reactivity' +import { Reaction, ReactionType } from '@modou/reactivity' -export function createTrackingData(reaction: typeof Reaction) { +export function createTrackingData(reaction: ReactionType) { const trackingData: IReactionTracking = { reaction, mounted: false, @@ -22,7 +22,7 @@ export interface ReactionCleanupTracking { */ addReactionToTrack( reactionTrackingRef: React.MutableRefObject, - reaction: typeof Reaction, + reaction: ReactionType, objectRetainedByReact: object, ): IReactionTracking recordReactionAsCommitted( @@ -34,7 +34,7 @@ export interface ReactionCleanupTracking { export interface IReactionTracking { /** The Reaction created during first render, which may be leaked */ - reaction: typeof Reaction + reaction: ReactionType /** * The time (in ticks) at which point we should dispose of the reaction * if this component hasn't yet been fully mounted. diff --git a/packages/reactivity/src/index.ts b/packages/reactivity/src/index.ts index 5c1dbcc..8b64f6a 100644 --- a/packages/reactivity/src/index.ts +++ b/packages/reactivity/src/index.ts @@ -1,11 +1,16 @@ +// @ts-ignore +// @ts-ignore import * as _mobx from 'mobx' let mobx: typeof _mobx = _mobx // TODO 判断浏览器环境还是Node环境 +// @ts-expect-error if (window.top?.__md_mobx__) { + // @ts-expect-error mobx = window.top.__md_mobx__ } +// @ts-expect-error window.__md_mobx__ = mobx export const action = mobx.action @@ -28,4 +33,8 @@ export const Reaction = mobx.Reaction export const when = mobx.when export const getDependencyTree = mobx.getDependencyTree -export { type IReactionDisposer, type AnnotationsMap } from 'mobx' +export { + type IReactionDisposer, + type AnnotationsMap, + Reaction as ReactionType, +} from 'mobx' diff --git a/packages/setters/src/components/string.tsx b/packages/setters/src/components/string.tsx index 518321f..fd375a2 100644 --- a/packages/setters/src/components/string.tsx +++ b/packages/setters/src/components/string.tsx @@ -15,7 +15,7 @@ type Props = BaseSetterProps export const StringSetter: FC = ({ value, onChange, options }) => { const Component = options?.textArea ? Input.TextArea : Input const [realValue, setRealValue] = useState(value) - const { run } = useDebounceFn(onChange, { wait: 200 }) + const { run } = useDebounceFn(onChange, { wait: 300 }) const debounceSetValue = useMemoizedFn( (valOrUpdater: ((currVal: any) => any) | any): void => { setRealValue(valOrUpdater) diff --git a/websites/workspace/src/features/app/components/ModuleManagerPage.tsx b/websites/workspace/src/features/app/components/ModuleManagerPage.tsx index 328926b..7c554d7 100644 --- a/websites/workspace/src/features/app/components/ModuleManagerPage.tsx +++ b/websites/workspace/src/features/app/components/ModuleManagerPage.tsx @@ -8,9 +8,9 @@ import { ComponentProps, FC } from 'react' import { createPortal } from 'react-dom' import { useNavigate, useParams } from 'react-router-dom' -import { Page, WidgetMetadata, generateId, useAppManager } from '@modou/core' +import { WidgetMetadata, generateId, useAppManager } from '@modou/core' import { mcss } from '@modou/css-in-js' -import { PageFile, WidgetFile } from '@modou/meta-vfs' +import { PageFile, PageFileMeta, WidgetFile } from '@modou/meta-vfs' import { Observer, observer } from '@modou/reactivity-react' import { rowWidgetMetadata } from '@modou/widgets-antd' @@ -30,7 +30,7 @@ const _ModuleManagerPage: FC<{ const dataSource = pages.filter((page) => { return page.meta.name.includes(searchVal) }) - const [form] = Form.useForm>() + const [form] = Form.useForm>() const renderListItem: ComponentProps>['renderItem'] = ( page, @@ -107,7 +107,7 @@ const _ModuleManagerPage: FC<{ <> {itemAddRef && createPortal( - > + > form={form} layout="horizontal" title="创建页面" diff --git a/websites/workspace/src/features/entity/components/EntitiesER.tsx b/websites/workspace/src/features/entity/components/EntitiesER.tsx index 4c7bb28..7b570d7 100644 --- a/websites/workspace/src/features/entity/components/EntitiesER.tsx +++ b/websites/workspace/src/features/entity/components/EntitiesER.tsx @@ -37,8 +37,7 @@ const useEntityNodeState = () => { type: 'EntityNode', data: { entity, - passiveEntityRelations: - passiveEntityRelations.get(entity.meta.name) || [], + passiveEntityRelations: passiveEntityRelations[entity.meta.name] || [], }, position: entity.meta.position, })), @@ -81,7 +80,7 @@ const useEntityNodeState = () => { data: { entity, passiveEntityRelations: - passiveEntityRelations.get(entity.meta.name) || [], + passiveEntityRelations[entity.meta.name] || [], }, position: entity.meta.position, } @@ -92,7 +91,7 @@ const useEntityNodeState = () => { data: { entity, passiveEntityRelations: - passiveEntityRelations.get(entity.meta.name) || [], + passiveEntityRelations[entity.meta.name] || [], }, position: entity.meta.position, } diff --git a/websites/workspace/src/features/entity/components/EntityFieldCreator.tsx b/websites/workspace/src/features/entity/components/EntityFieldCreator.tsx index 603c9cd..65c0f55 100644 --- a/websites/workspace/src/features/entity/components/EntityFieldCreator.tsx +++ b/websites/workspace/src/features/entity/components/EntityFieldCreator.tsx @@ -188,7 +188,7 @@ const _EntityFieldCreator: ForwardRefRenderFunction< onFinish={async (formData) => { switch (mode) { case 'create': { - const entity = app.entityMap.get(entityId)! + const entity = app.entityMap[entityId]! EntityFieldFile.create( { ...formData, @@ -199,7 +199,7 @@ const _EntityFieldCreator: ForwardRefRenderFunction< break } case 'edit': { - const entity = app.entityMap.get(entityId)! + const entity = app.entityMap[entityId]! entity.entityFields.forEach((field) => { if (field.meta.id === entityFieldId) { field.updateMeta({ diff --git a/websites/workspace/src/features/entity/components/EntityFields.tsx b/websites/workspace/src/features/entity/components/EntityFields.tsx index d9ebf18..efce5f4 100644 --- a/websites/workspace/src/features/entity/components/EntityFields.tsx +++ b/websites/workspace/src/features/entity/components/EntityFields.tsx @@ -16,7 +16,7 @@ const _EntityFields: FC<{ useRef(null) const { app } = useAppManager() - const entity = app.entityMap.get(entityId)! + const entity = app.entityMap[entityId]! const columns: ColumnsType = [ { diff --git a/websites/workspace/src/features/entity/hooks/useEntityCreator.ts b/websites/workspace/src/features/entity/hooks/useEntityCreator.ts index b894592..5678496 100644 --- a/websites/workspace/src/features/entity/hooks/useEntityCreator.ts +++ b/websites/workspace/src/features/entity/hooks/useEntityCreator.ts @@ -12,7 +12,7 @@ export const useEntityCreator = () => { const onSubmitEntity = (entity: EntityFileMeta) => { // 编辑 if (entity.id) { - app.entityMap.get(entity.id)!.updateMeta(entity) + app.entityMap[entity.id].updateMeta(entity) } else { const maxX = Math.max( ...app.entities.map((entity) => entity.meta.position.x), diff --git a/websites/workspace/src/features/entity/routers/Entity.tsx b/websites/workspace/src/features/entity/routers/Entity.tsx index 43dd8e1..ccb06f1 100644 --- a/websites/workspace/src/features/entity/routers/Entity.tsx +++ b/websites/workspace/src/features/entity/routers/Entity.tsx @@ -50,7 +50,7 @@ const _Entity: FC = () => { }) const { app } = useAppManager() const { entityId } = useParams() - const entity = app.entityMap.get(entityId!)! + const entity = app.entityMap[entityId!] const { open, setFalse, setTrue, onSubmitEntity, form } = useEntityCreator() const buildTabPanel = (tabKey: EntityModuleTabKeyEnum) => { diff --git a/widgets/antd/src/ButtonWidget/constants.ts b/widgets/antd/src/ButtonWidget/constants.ts index e599706..ae9025b 100644 --- a/widgets/antd/src/ButtonWidget/constants.ts +++ b/widgets/antd/src/ButtonWidget/constants.ts @@ -64,7 +64,7 @@ export const typeOptions: MRSelectOptions = [ value: ButtonWidgetTypeEnum.Text, }, { - label: '连接按钮', + label: '链接按钮', value: ButtonWidgetTypeEnum.Link, }, { From aac9b71d195b632cff118ff0ac36ba23cdc861f9 Mon Sep 17 00:00:00 2001 From: liulei Date: Sat, 21 Jan 2023 17:44:25 +0800 Subject: [PATCH 07/68] fix: ts type --- packages/reactivity/src/index.ts | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/packages/reactivity/src/index.ts b/packages/reactivity/src/index.ts index 8b64f6a..3dfc8c5 100644 --- a/packages/reactivity/src/index.ts +++ b/packages/reactivity/src/index.ts @@ -1,17 +1,14 @@ -// @ts-ignore -// @ts-ignore import * as _mobx from 'mobx' +const MD_MOBX_PATH = '__md_mobx__' + let mobx: typeof _mobx = _mobx // TODO 判断浏览器环境还是Node环境 -// @ts-expect-error -if (window.top?.__md_mobx__) { - // @ts-expect-error - mobx = window.top.__md_mobx__ +if (window.top && Reflect.has(window.top, MD_MOBX_PATH)) { + mobx = Reflect.get(window.top, MD_MOBX_PATH) } -// @ts-expect-error -window.__md_mobx__ = mobx +Reflect.set(window, MD_MOBX_PATH, mobx) export const action = mobx.action export const autorun = mobx.autorun From 063945e21e168c8c30c1d0c30c75c3592d369e4b Mon Sep 17 00:00:00 2001 From: liulei Date: Sat, 21 Jan 2023 20:03:50 +0800 Subject: [PATCH 08/68] =?UTF-8?q?fix(designer):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=E6=B7=BB=E5=8A=A0=E4=B8=A4=E9=81=8D=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/meta-vfs/package.json | 3 + packages/meta-vfs/src/AppFile/index.ts | 16 +++++ packages/meta-vfs/src/Foo/index.md | 9 --- packages/meta-vfs/src/Foo/index.tsx | 86 ------------------------- packages/meta-vfs/src/PageFile/index.ts | 3 +- packages/meta-vfs/src/index.ts | 1 - pnpm-lock.yaml | 9 +++ 7 files changed, 29 insertions(+), 98 deletions(-) delete mode 100644 packages/meta-vfs/src/Foo/index.md delete mode 100644 packages/meta-vfs/src/Foo/index.tsx diff --git a/packages/meta-vfs/package.json b/packages/meta-vfs/package.json index 7955180..9f22f0a 100644 --- a/packages/meta-vfs/package.json +++ b/packages/meta-vfs/package.json @@ -67,5 +67,8 @@ "react": "^18.0.0", "react-dom": "^18.0.0", "stylelint": "^14.9.1" + }, + "dependencies": { + "mobx-persist-store": "^1.1.3" } } diff --git a/packages/meta-vfs/src/AppFile/index.ts b/packages/meta-vfs/src/AppFile/index.ts index f78a221..1d1b900 100644 --- a/packages/meta-vfs/src/AppFile/index.ts +++ b/packages/meta-vfs/src/AppFile/index.ts @@ -1,4 +1,5 @@ import { isArray, keyBy } from 'lodash' +import { makePersistable } from 'mobx-persist-store' import { action, @@ -33,6 +34,21 @@ export class AppFile extends BaseFile { deleteEntity: action, deletePage: action, }) + void makePersistable(this, { + name: `${meta.id}`, + properties: [ + { + key: 'meta', + serialize: () => { + return this.toJSON() + }, + deserialize: () => { + return {} as unknown as AppFileMeta + }, + }, + ], + storage: window.localStorage, + }) } subFileMap: FileMap = { diff --git a/packages/meta-vfs/src/Foo/index.md b/packages/meta-vfs/src/Foo/index.md deleted file mode 100644 index 64aef1a..0000000 --- a/packages/meta-vfs/src/Foo/index.md +++ /dev/null @@ -1,9 +0,0 @@ -# Foo - -This is an example component. - -```jsx -import { Foo } from '@modou/meta-vfs'; - -export default () => -``` diff --git a/packages/meta-vfs/src/Foo/index.tsx b/packages/meta-vfs/src/Foo/index.tsx deleted file mode 100644 index 133ad48..0000000 --- a/packages/meta-vfs/src/Foo/index.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import React, { type FC } from 'react' - -import { generateId } from '@modou/core' -import { autorun, runInAction } from '@modou/reactivity' -import { observer } from '@modou/reactivity-react' - -import { AppFile } from '../AppFile' -import { PageFile } from '../PageFile' -import { WidgetFile } from '../WidgetFile' - -const appFile = AppFile.create({ - name: 'App_Demo', - version: '0.0.0', - id: generateId(), -}) - -runInAction(() => { - const page1 = PageFile.create( - { - name: 'Page_Demo_1', - id: generateId(), - rootWidgetId: '0', - }, - appFile, - ) - const page2 = PageFile.create( - { - name: 'Page_Demo_2', - id: generateId(), - rootWidgetId: '0', - }, - appFile, - ) - // const appFile = AppFile.formJSON(mock_metadata as any) - WidgetFile.create( - { - name: '按钮_1', - id: generateId(), - slots: {}, - props: { - title: '提交', - }, - type: 'Button', - }, - page1, - ) - WidgetFile.create( - { - name: '输入框_2', - id: generateId(), - slots: {}, - props: { - title: '提交', - }, - type: 'Input', - }, - page2, - ) -}) -const test = () => { - // console.log(JSON.stringify(appFile)) - // console.log(appFile) - appFile.pages[0].meta.name = '撒阿萨' + Math.random() - // [0].meta.name = '撒阿萨' + Math.random() -} - -autorun(() => { - // console.log('autorun', appFile.test[0]) -}) -// autorun(() => { -// console.log('autorun', appFile.meta.name) -// }) -// effect(() => { -// console.log(appFile.pages[0]?.meta?.name) -// }) -// effect(() => { -// console.log(appFile.pages[0]) -// }) - -const Foo: FC<{ title: string }> = observer(() => ( -

- -
-)) - -export default Foo diff --git a/packages/meta-vfs/src/PageFile/index.ts b/packages/meta-vfs/src/PageFile/index.ts index 71a8249..0336a64 100644 --- a/packages/meta-vfs/src/PageFile/index.ts +++ b/packages/meta-vfs/src/PageFile/index.ts @@ -99,12 +99,11 @@ export class PageFile extends BaseFile { targetPosition: number targetSlotPath: string }) { - const sourceWidget = WidgetFile.create(sourceWidgetMeta, this) const targetWidget = this.widgetMap[targetWidgetId] if (!targetWidget) { return } - this.widgets.push(sourceWidget) + const sourceWidget = WidgetFile.create(sourceWidgetMeta, this) targetWidget.meta.slots[targetSlotPath].splice( targetPosition, 0, diff --git a/packages/meta-vfs/src/index.ts b/packages/meta-vfs/src/index.ts index d97c299..c752504 100644 --- a/packages/meta-vfs/src/index.ts +++ b/packages/meta-vfs/src/index.ts @@ -8,7 +8,6 @@ configure({ reactionRequiresObservable: true, }) -export { default as Foo } from './Foo' export * from './AppFile' export * from './PageFile' export * from './EntityFile' diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 96dd584..9384a94 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -229,12 +229,15 @@ importers: father: ^4.1.0 husky: ^8.0.1 lint-staged: ^13.0.3 + mobx-persist-store: ^1.1.3 prettier: ^2.7.1 prettier-plugin-organize-imports: ^3.0.0 prettier-plugin-packagejson: ^2.2.18 react: ^18.0.0 react-dom: ^18.0.0 stylelint: ^14.9.1 + dependencies: + mobx-persist-store: 1.1.3 devDependencies: '@commitlint/cli': 17.3.0 '@commitlint/config-conventional': 17.3.0 @@ -11331,6 +11334,12 @@ packages: minimist: 1.2.6 dev: true + /mobx-persist-store/1.1.3: + resolution: {integrity: sha512-P5B4CNCgAlKZ5dLqwcKYx9qmSc2b53iQTBKkH//7bXzgbsg0+bG4LJ0rPeIx/8/J5lduzqC7/oT+kuNaeHMMqQ==} + peerDependencies: + mobx: '*' + dev: false + /mobx/6.7.0: resolution: {integrity: sha512-1kBLBdSNG2bA522HQdbsTvwAwYf9hq9FWxmlhX7wTsJUAI54907J+ozfGW+LoYUo06vjit748g6QH1AAGLNebw==} dev: false From aa3518f4e09edd21548c59d56ee7799968f40772 Mon Sep 17 00:00:00 2001 From: liulei Date: Sun, 22 Jan 2023 06:17:53 +0800 Subject: [PATCH 09/68] =?UTF-8?q?refactor:=20=E7=BB=9F=E4=B8=80=E7=94=9F?= =?UTF-8?q?=E6=88=90=20widget=20instance?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/core/src/widget/WidgetMetadata.ts | 17 +++++++++++++++-- widgets/antd/src/ButtonWidget/metadata.tsx | 9 --------- widgets/antd/src/ColWidget/metadata.tsx | 9 --------- widgets/antd/src/FormWidget/metadata.tsx | 9 --------- widgets/antd/src/InputWidget/metadata.tsx | 5 ----- widgets/antd/src/RowWidget/metadata.tsx | 9 --------- widgets/antd/src/TableWidget/metadata.tsx | 9 --------- widgets/antd/src/_/types.ts | 2 +- 8 files changed, 16 insertions(+), 53 deletions(-) diff --git a/packages/core/src/widget/WidgetMetadata.ts b/packages/core/src/widget/WidgetMetadata.ts index 9f2a570..7a7b884 100644 --- a/packages/core/src/widget/WidgetMetadata.ts +++ b/packages/core/src/widget/WidgetMetadata.ts @@ -46,7 +46,8 @@ interface BaseWidgetMetadata< setters: Record>> mrPropsScheme: PropsMRScheme mrStateScheme: StateMRScheme - initState: ( + // TODO 通过 props 和 state 的类型对比判断 initState 是否是必传的 + initState?: ( widget: mr.infer, ) => Omit< InferWidgetState, @@ -54,6 +55,7 @@ interface BaseWidgetMetadata< | 'renderSlotPaths' | 'renderSlots' | 'updateState' + | 'instance' > } @@ -101,7 +103,18 @@ export class WidgetMetadata< // TODO FIX TYPE this.setters = setters this.icon = icon - this.initState = initState + // TODO IMPORTMANT 完善类型定义 + this.initState = ((...args: [{ id: string }]) => { + const { id } = args[0] + return { + instance: { + id, + widgetId: id, + initialized: true, + }, + ...(initState?.(...args) ?? {}), + } + }) as unknown as typeof initState } version diff --git a/widgets/antd/src/ButtonWidget/metadata.tsx b/widgets/antd/src/ButtonWidget/metadata.tsx index c8e7bd3..91296de 100644 --- a/widgets/antd/src/ButtonWidget/metadata.tsx +++ b/widgets/antd/src/ButtonWidget/metadata.tsx @@ -120,13 +120,4 @@ export const buttonWidgetMetadata = WidgetMetadata.createMetadata({ mrStateScheme: MRSchemeButtonWidgetState, slots: {}, setters: {}, - initState: ({ id }) => { - return { - instance: { - id, - widgetId: id, - initialized: true, - }, - } - }, }) diff --git a/widgets/antd/src/ColWidget/metadata.tsx b/widgets/antd/src/ColWidget/metadata.tsx index 9bf7c02..f2d179a 100644 --- a/widgets/antd/src/ColWidget/metadata.tsx +++ b/widgets/antd/src/ColWidget/metadata.tsx @@ -43,13 +43,4 @@ export const colWidgetMetadata = WidgetMetadata.createMetadata< setters: {}, mrPropsScheme: MRSchemeColWidgetProps, mrStateScheme: MRSchemeColWidgetState, - initState: ({ id }) => { - return { - instance: { - id, - widgetId: id, - initialized: true, - }, - } - }, }) diff --git a/widgets/antd/src/FormWidget/metadata.tsx b/widgets/antd/src/FormWidget/metadata.tsx index 6a29962..84dfaf4 100644 --- a/widgets/antd/src/FormWidget/metadata.tsx +++ b/widgets/antd/src/FormWidget/metadata.tsx @@ -56,13 +56,4 @@ export const formWidgetMetadata = WidgetMetadata.createMetadata< setters: {}, mrPropsScheme: MRSchemeFormWidgetProps, mrStateScheme: MRSchemeFormWidgetState, - initState: ({ id }) => { - return { - instance: { - id, - widgetId: id, - initialized: true, - }, - } - }, }) diff --git a/widgets/antd/src/InputWidget/metadata.tsx b/widgets/antd/src/InputWidget/metadata.tsx index beb940d..3b66c9e 100644 --- a/widgets/antd/src/InputWidget/metadata.tsx +++ b/widgets/antd/src/InputWidget/metadata.tsx @@ -46,11 +46,6 @@ export const inputWidgetMetadata = WidgetMetadata.createMetadata({ initState: ({ id, props }) => { return { value: props.defaultValue, - instance: { - id, - widgetId: id, - initialized: true, - }, } }, }) diff --git a/widgets/antd/src/RowWidget/metadata.tsx b/widgets/antd/src/RowWidget/metadata.tsx index d5c9830..f75effd 100644 --- a/widgets/antd/src/RowWidget/metadata.tsx +++ b/widgets/antd/src/RowWidget/metadata.tsx @@ -70,13 +70,4 @@ export const rowWidgetMetadata = WidgetMetadata.createMetadata< }, }, setters: {}, - initState: ({ id }) => { - return { - instance: { - id, - widgetId: id, - initialized: true, - }, - } - }, }) diff --git a/widgets/antd/src/TableWidget/metadata.tsx b/widgets/antd/src/TableWidget/metadata.tsx index 4d00aa3..34625bb 100644 --- a/widgets/antd/src/TableWidget/metadata.tsx +++ b/widgets/antd/src/TableWidget/metadata.tsx @@ -74,13 +74,4 @@ export const tableWidgetMetadata = WidgetMetadata.createMetadata< }, mrPropsScheme: MRSchemeTableWidgetProps, mrStateScheme: MRSchemeTableWidgetState, - initState: ({ id }) => { - return { - instance: { - id, - widgetId: id, - initialized: true, - }, - } - }, }) diff --git a/widgets/antd/src/_/types.ts b/widgets/antd/src/_/types.ts index 691d11a..3c1602b 100644 --- a/widgets/antd/src/_/types.ts +++ b/widgets/antd/src/_/types.ts @@ -1,6 +1,6 @@ // import { SelectSetter } from '@modou/setters' // export type MRSelectOptions = Parameters[0]['options'] -import { FC, ReactNode } from 'react' +import { ReactNode } from 'react' import { MRTypeAny, mr } from '@modou/refine' From ec8e81097b50c6ddb5164ef70a40dbdcd772c1fb Mon Sep 17 00:00:00 2001 From: liulei Date: Sun, 22 Jan 2023 06:19:59 +0800 Subject: [PATCH 10/68] chore: udpate antd --- package.json | 4 +- pnpm-lock.yaml | 156 ++++++++++++++++++++++++++----------------------- 2 files changed, 84 insertions(+), 76 deletions(-) diff --git a/package.json b/package.json index 864d885..a98dfdf 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "vite": "^4.0.3" }, "dependencies": { - "@ant-design/icons": "^4.8.0", + "@ant-design/icons": "^5.0.1", "@ant-design/pro-components": "^2.3.52", "@modou/compile-core": "workspace:^0.0.1", "@modou/core": "workspace:^1.0.0", @@ -54,7 +54,7 @@ "@vue/compiler-core": "^3.2.45", "@vue/runtime-core": "^3.2.45", "ahooks": "^3.7.0", - "antd": "^5.1.5", + "antd": "^5.1.6", "axios": "^1.1.3", "flat": "^5.0.2", "handlebars": "^4.7.7", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9384a94..7349e71 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,7 +9,7 @@ importers: .: specifiers: - '@ant-design/icons': ^4.8.0 + '@ant-design/icons': ^5.0.1 '@ant-design/pro-components': ^2.3.52 '@emotion/babel-plugin': ^11.10.5 '@modou/compile-core': workspace:^0.0.1 @@ -34,7 +34,7 @@ importers: '@vue/compiler-core': ^3.2.45 '@vue/runtime-core': ^3.2.45 ahooks: ^3.7.0 - antd: ^5.1.5 + antd: ^5.1.6 autoprefixer: ^10.4.8 axios: ^1.1.3 commitizen: 4.2.5 @@ -67,8 +67,8 @@ importers: typescript: ^4.7.4 vite: ^4.0.3 dependencies: - '@ant-design/icons': 4.8.0_biqbaboplfbrettd7655fr4n2y - '@ant-design/pro-components': 2.3.52_5kykwr4aqmxcvhhfl2j2qf3uya + '@ant-design/icons': 5.0.1_biqbaboplfbrettd7655fr4n2y + '@ant-design/pro-components': 2.3.52_6pxft4cxqls2twurebs67c4zfy '@modou/compile-core': link:packages/compiler-core '@modou/core': link:packages/core '@modou/css-in-js': link:packages/css-in-js @@ -85,7 +85,7 @@ importers: '@vue/compiler-core': 3.2.45 '@vue/runtime-core': 3.2.45 ahooks: 3.7.1_react@18.2.0 - antd: 5.1.5_biqbaboplfbrettd7655fr4n2y + antd: 5.1.6_biqbaboplfbrettd7655fr4n2y axios: 1.1.3 flat: 5.0.2 handlebars: 4.7.7 @@ -126,6 +126,9 @@ importers: typescript: 4.8.4 vite: 4.0.3 + packages/asset-vfs: + specifiers: {} + packages/canvas-designer: specifiers: {} @@ -219,6 +222,9 @@ importers: '@emotion/css': 11.10.0 '@emotion/react': 11.10.4 + packages/evaluate: + specifiers: {} + packages/meta-vfs: specifiers: '@commitlint/cli': ^17.1.2 @@ -343,6 +349,9 @@ importers: packages/simulator: specifiers: {} + packages/state-manager: + specifiers: {} + websites/runtime: specifiers: {} @@ -408,8 +417,8 @@ packages: '@ctrl/tinycolor': 3.4.1 dev: false - /@ant-design/cssinjs/1.5.0_biqbaboplfbrettd7655fr4n2y: - resolution: {integrity: sha512-auGB6HK318lJOFMMcXTlYZuNL3mrx0wPkoFzOG4GkzqlOfvdjkroAXj5tuaM8mAoPkFPGqXYewICu0REex1phw==} + /@ant-design/cssinjs/1.5.6_biqbaboplfbrettd7655fr4n2y: + resolution: {integrity: sha512-1S7LUPC9BMyQ/CUYgzfePJJwEfsbVHJe3Tpd9zhujTxRM/6LYpN9N4FTaPHVqpnPazm0S2vG0WBkh2T5Erwuug==} peerDependencies: react: '>=16.0.0' react-dom: '>=16.0.0' @@ -444,8 +453,8 @@ packages: react-dom: 18.2.0_react@18.2.0 dev: false - /@ant-design/icons/5.0.0_biqbaboplfbrettd7655fr4n2y: - resolution: {integrity: sha512-dPUlZtsIffBrDyFwM+tuO4PWi1DPgGgd10ASistPhLpr1WyssadfhChWs/mICVkCm5PaRm/foMkE1x3xw4OPZw==} + /@ant-design/icons/5.0.1_biqbaboplfbrettd7655fr4n2y: + resolution: {integrity: sha512-ZyF4ksXCcdtwA/1PLlnFLcF/q8/MhwxXhKHh4oCHDA4Ip+ZzAHoICtyp4wZWfiCVDP0yuz3HsjyvuldHFb3wjA==} engines: {node: '>=8'} peerDependencies: react: '>=16.0.0' @@ -460,17 +469,17 @@ packages: react-dom: 18.2.0_react@18.2.0 dev: false - /@ant-design/pro-card/2.1.10_5kykwr4aqmxcvhhfl2j2qf3uya: + /@ant-design/pro-card/2.1.10_6pxft4cxqls2twurebs67c4zfy: resolution: {integrity: sha512-edajGd2/35w73tLC7yMZf2/8tWg4Wz9pmN6jQgFo+QIRXoaHd5zpeQaOMxZojeqzCxTH0Qt60YpeLp/S+ahupQ==} peerDependencies: antd: '>=4.23.0' react: '>=16.9.0' dependencies: '@ant-design/icons': 4.8.0_biqbaboplfbrettd7655fr4n2y - '@ant-design/pro-provider': 2.4.0_5kykwr4aqmxcvhhfl2j2qf3uya - '@ant-design/pro-utils': 2.5.4_5kykwr4aqmxcvhhfl2j2qf3uya + '@ant-design/pro-provider': 2.4.0_6pxft4cxqls2twurebs67c4zfy + '@ant-design/pro-utils': 2.5.4_6pxft4cxqls2twurebs67c4zfy '@babel/runtime': 7.20.7 - antd: 5.1.5_biqbaboplfbrettd7655fr4n2y + antd: 5.1.6_biqbaboplfbrettd7655fr4n2y classnames: 2.3.2 omit.js: 2.0.2 rc-resize-observer: 1.2.0_biqbaboplfbrettd7655fr4n2y @@ -480,25 +489,25 @@ packages: - react-dom dev: false - /@ant-design/pro-components/2.3.52_5kykwr4aqmxcvhhfl2j2qf3uya: + /@ant-design/pro-components/2.3.52_6pxft4cxqls2twurebs67c4zfy: resolution: {integrity: sha512-df51Xi59QRXXIc5uMcO/7/tPjNziGt1w40860yCztFBNCoNc9B+xvDwsuRWgvRL1yqM4SZL1Al7T392CtyESSg==} peerDependencies: antd: '>=4.23.0' react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@ant-design/pro-card': 2.1.10_5kykwr4aqmxcvhhfl2j2qf3uya - '@ant-design/pro-descriptions': 2.0.44_5kykwr4aqmxcvhhfl2j2qf3uya - '@ant-design/pro-field': 2.2.5_5kykwr4aqmxcvhhfl2j2qf3uya - '@ant-design/pro-form': 2.5.4_5kykwr4aqmxcvhhfl2j2qf3uya - '@ant-design/pro-layout': 7.6.1_5kykwr4aqmxcvhhfl2j2qf3uya - '@ant-design/pro-list': 2.0.45_5kykwr4aqmxcvhhfl2j2qf3uya - '@ant-design/pro-provider': 2.4.0_5kykwr4aqmxcvhhfl2j2qf3uya - '@ant-design/pro-skeleton': 2.0.7_5kykwr4aqmxcvhhfl2j2qf3uya - '@ant-design/pro-table': 3.2.12_5kykwr4aqmxcvhhfl2j2qf3uya - '@ant-design/pro-utils': 2.5.4_5kykwr4aqmxcvhhfl2j2qf3uya + '@ant-design/pro-card': 2.1.10_6pxft4cxqls2twurebs67c4zfy + '@ant-design/pro-descriptions': 2.0.44_6pxft4cxqls2twurebs67c4zfy + '@ant-design/pro-field': 2.2.5_6pxft4cxqls2twurebs67c4zfy + '@ant-design/pro-form': 2.5.4_6pxft4cxqls2twurebs67c4zfy + '@ant-design/pro-layout': 7.6.1_6pxft4cxqls2twurebs67c4zfy + '@ant-design/pro-list': 2.0.45_6pxft4cxqls2twurebs67c4zfy + '@ant-design/pro-provider': 2.4.0_6pxft4cxqls2twurebs67c4zfy + '@ant-design/pro-skeleton': 2.0.7_6pxft4cxqls2twurebs67c4zfy + '@ant-design/pro-table': 3.2.12_6pxft4cxqls2twurebs67c4zfy + '@ant-design/pro-utils': 2.5.4_6pxft4cxqls2twurebs67c4zfy '@babel/runtime': 7.20.7 - antd: 5.1.5_biqbaboplfbrettd7655fr4n2y + antd: 5.1.6_biqbaboplfbrettd7655fr4n2y react: 18.2.0 react-dom: 18.2.0_react@18.2.0 transitivePeerDependencies: @@ -506,18 +515,18 @@ packages: - rc-field-form dev: false - /@ant-design/pro-descriptions/2.0.44_5kykwr4aqmxcvhhfl2j2qf3uya: + /@ant-design/pro-descriptions/2.0.44_6pxft4cxqls2twurebs67c4zfy: resolution: {integrity: sha512-UEwZbvjOBTxWvPGv8qb3i+Q5czuHFYwRokSgVzVyS2el6xLYr4ZjG0a2CQsjbBnIb0MvZCfnkIn+W0XD/bjS3g==} peerDependencies: antd: '>=4.23.0' react: '>=16.9.0' dependencies: - '@ant-design/pro-field': 2.2.5_5kykwr4aqmxcvhhfl2j2qf3uya - '@ant-design/pro-form': 2.5.4_5kykwr4aqmxcvhhfl2j2qf3uya - '@ant-design/pro-skeleton': 2.0.7_5kykwr4aqmxcvhhfl2j2qf3uya - '@ant-design/pro-utils': 2.5.4_5kykwr4aqmxcvhhfl2j2qf3uya + '@ant-design/pro-field': 2.2.5_6pxft4cxqls2twurebs67c4zfy + '@ant-design/pro-form': 2.5.4_6pxft4cxqls2twurebs67c4zfy + '@ant-design/pro-skeleton': 2.0.7_6pxft4cxqls2twurebs67c4zfy + '@ant-design/pro-utils': 2.5.4_6pxft4cxqls2twurebs67c4zfy '@babel/runtime': 7.20.7 - antd: 5.1.5_biqbaboplfbrettd7655fr4n2y + antd: 5.1.6_biqbaboplfbrettd7655fr4n2y rc-util: 5.27.1_biqbaboplfbrettd7655fr4n2y react: 18.2.0 use-json-comparison: 1.0.6_react@18.2.0 @@ -527,18 +536,18 @@ packages: - react-dom dev: false - /@ant-design/pro-field/2.2.5_5kykwr4aqmxcvhhfl2j2qf3uya: + /@ant-design/pro-field/2.2.5_6pxft4cxqls2twurebs67c4zfy: resolution: {integrity: sha512-7Rp0uRhdCUnOFKXkId5wCjjQJBWo0sMhOQs10y40/hNpGpTEpVuEmJo2Jx4Sj2hj/g663WOUSF0YBK7PhFtTFA==} peerDependencies: antd: '>=4.23.0' react: '>=16.9.0' dependencies: '@ant-design/icons': 4.8.0_biqbaboplfbrettd7655fr4n2y - '@ant-design/pro-provider': 2.4.0_5kykwr4aqmxcvhhfl2j2qf3uya - '@ant-design/pro-utils': 2.5.4_5kykwr4aqmxcvhhfl2j2qf3uya + '@ant-design/pro-provider': 2.4.0_6pxft4cxqls2twurebs67c4zfy + '@ant-design/pro-utils': 2.5.4_6pxft4cxqls2twurebs67c4zfy '@babel/runtime': 7.20.7 '@chenshuai2144/sketch-color': 1.0.8_react@18.2.0 - antd: 5.1.5_biqbaboplfbrettd7655fr4n2y + antd: 5.1.6_biqbaboplfbrettd7655fr4n2y classnames: 2.3.2 dayjs: 1.11.5 lodash.tonumber: 4.0.3 @@ -550,7 +559,7 @@ packages: - react-dom dev: false - /@ant-design/pro-form/2.5.4_5kykwr4aqmxcvhhfl2j2qf3uya: + /@ant-design/pro-form/2.5.4_6pxft4cxqls2twurebs67c4zfy: resolution: {integrity: sha512-Udzs2BLLHK9xhryB0GqE4FvC0KVjiD88z0NqSkJT1AfFMbBn5ERUh2TJ87vfSc8CS4UPGGeU868YzXVMR9AkbA==} peerDependencies: '@types/lodash.merge': ^4.6.7 @@ -563,12 +572,12 @@ packages: optional: true dependencies: '@ant-design/icons': 4.8.0_biqbaboplfbrettd7655fr4n2y - '@ant-design/pro-field': 2.2.5_5kykwr4aqmxcvhhfl2j2qf3uya - '@ant-design/pro-provider': 2.4.0_5kykwr4aqmxcvhhfl2j2qf3uya - '@ant-design/pro-utils': 2.5.4_5kykwr4aqmxcvhhfl2j2qf3uya + '@ant-design/pro-field': 2.2.5_6pxft4cxqls2twurebs67c4zfy + '@ant-design/pro-provider': 2.4.0_6pxft4cxqls2twurebs67c4zfy + '@ant-design/pro-utils': 2.5.4_6pxft4cxqls2twurebs67c4zfy '@babel/runtime': 7.20.7 '@umijs/use-params': 1.0.9_react@18.2.0 - antd: 5.1.5_biqbaboplfbrettd7655fr4n2y + antd: 5.1.6_biqbaboplfbrettd7655fr4n2y classnames: 2.3.2 lodash.merge: 4.6.2 omit.js: 2.0.2 @@ -580,7 +589,7 @@ packages: use-media-antd-query: 1.1.0_react@18.2.0 dev: false - /@ant-design/pro-layout/7.6.1_5kykwr4aqmxcvhhfl2j2qf3uya: + /@ant-design/pro-layout/7.6.1_6pxft4cxqls2twurebs67c4zfy: resolution: {integrity: sha512-MNmOALRmVbAUbsbJSmUdXyKgvxyTG1pp9YYwway5AqKz28PdfDp6HhqrvCE7zRnxIaJWv9Vb6IZ/XqstI5zDeg==} peerDependencies: antd: '>=4.23.0' @@ -588,12 +597,12 @@ packages: react-dom: '>=16.9.0' dependencies: '@ant-design/icons': 4.8.0_biqbaboplfbrettd7655fr4n2y - '@ant-design/pro-provider': 2.4.0_5kykwr4aqmxcvhhfl2j2qf3uya - '@ant-design/pro-utils': 2.5.4_5kykwr4aqmxcvhhfl2j2qf3uya + '@ant-design/pro-provider': 2.4.0_6pxft4cxqls2twurebs67c4zfy + '@ant-design/pro-utils': 2.5.4_6pxft4cxqls2twurebs67c4zfy '@babel/runtime': 7.20.7 '@umijs/route-utils': 4.0.1 '@umijs/use-params': 1.0.9_react@18.2.0 - antd: 5.1.5_biqbaboplfbrettd7655fr4n2y + antd: 5.1.6_biqbaboplfbrettd7655fr4n2y classnames: 2.3.2 lodash.merge: 4.6.2 omit.js: 2.0.2 @@ -609,7 +618,7 @@ packages: warning: 4.0.3 dev: false - /@ant-design/pro-list/2.0.45_5kykwr4aqmxcvhhfl2j2qf3uya: + /@ant-design/pro-list/2.0.45_6pxft4cxqls2twurebs67c4zfy: resolution: {integrity: sha512-jGcTqL+ziAKZ71NERmbfFST+BoOIyVy6NQNDvTNa2V/r2ZYR+eLStEcRfTp0MyWaWillXJqBIi3jNhDUIXWVhg==} peerDependencies: antd: '>=4.23.0' @@ -617,11 +626,11 @@ packages: react-dom: '>=16.9.0' dependencies: '@ant-design/icons': 4.8.0_biqbaboplfbrettd7655fr4n2y - '@ant-design/pro-card': 2.1.10_5kykwr4aqmxcvhhfl2j2qf3uya - '@ant-design/pro-field': 2.2.5_5kykwr4aqmxcvhhfl2j2qf3uya - '@ant-design/pro-table': 3.2.12_5kykwr4aqmxcvhhfl2j2qf3uya + '@ant-design/pro-card': 2.1.10_6pxft4cxqls2twurebs67c4zfy + '@ant-design/pro-field': 2.2.5_6pxft4cxqls2twurebs67c4zfy + '@ant-design/pro-table': 3.2.12_6pxft4cxqls2twurebs67c4zfy '@babel/runtime': 7.20.7 - antd: 5.1.5_biqbaboplfbrettd7655fr4n2y + antd: 5.1.6_biqbaboplfbrettd7655fr4n2y classnames: 2.3.2 dayjs: 1.11.5 rc-resize-observer: 1.2.0_biqbaboplfbrettd7655fr4n2y @@ -635,24 +644,24 @@ packages: - rc-field-form dev: false - /@ant-design/pro-provider/2.4.0_5kykwr4aqmxcvhhfl2j2qf3uya: + /@ant-design/pro-provider/2.4.0_6pxft4cxqls2twurebs67c4zfy: resolution: {integrity: sha512-toz3F7moI6o99DCaEJRQv/jYrQXYlxiM3RpTb5L+zXYwc4hFxfv8Jj2Qm6XMX0DRZgCsDt5KK7R+9c9LzoNxbg==} peerDependencies: antd: '>=4.23.0' react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@ant-design/cssinjs': 1.5.0_biqbaboplfbrettd7655fr4n2y + '@ant-design/cssinjs': 1.5.6_biqbaboplfbrettd7655fr4n2y '@babel/runtime': 7.20.7 '@ctrl/tinycolor': 3.4.1 - antd: 5.1.5_biqbaboplfbrettd7655fr4n2y + antd: 5.1.6_biqbaboplfbrettd7655fr4n2y rc-util: 5.27.1_biqbaboplfbrettd7655fr4n2y react: 18.2.0 react-dom: 18.2.0_react@18.2.0 swr: 2.0.0_react@18.2.0 dev: false - /@ant-design/pro-skeleton/2.0.7_5kykwr4aqmxcvhhfl2j2qf3uya: + /@ant-design/pro-skeleton/2.0.7_6pxft4cxqls2twurebs67c4zfy: resolution: {integrity: sha512-7RoCUVgWDTGrWeNuFlscsxrrXc5jshYXk6gjkQKospR0hQ1AK/aWlkttAAaqDFZlvPxSyLu8w11TmquRuYcNcg==} peerDependencies: antd: '>=4.23.0' @@ -660,13 +669,13 @@ packages: react-dom: '>=16.9.0' dependencies: '@babel/runtime': 7.20.7 - antd: 5.1.5_biqbaboplfbrettd7655fr4n2y + antd: 5.1.6_biqbaboplfbrettd7655fr4n2y react: 18.2.0 react-dom: 18.2.0_react@18.2.0 use-media-antd-query: 1.1.0_react@18.2.0 dev: false - /@ant-design/pro-table/3.2.12_5kykwr4aqmxcvhhfl2j2qf3uya: + /@ant-design/pro-table/3.2.12_6pxft4cxqls2twurebs67c4zfy: resolution: {integrity: sha512-jhfKBtU5DnOlj0eL/Tz3D5j9DZt6KeWCcaJOA/FDr/ZTj5ROUThhK5DqzeLjR9O/DTBCgiwB8Vpiqt0uWPWlXw==} peerDependencies: antd: '>=4.23.0' @@ -675,13 +684,13 @@ packages: react-dom: '>=16.9.0' dependencies: '@ant-design/icons': 4.8.0_biqbaboplfbrettd7655fr4n2y - '@ant-design/pro-card': 2.1.10_5kykwr4aqmxcvhhfl2j2qf3uya - '@ant-design/pro-field': 2.2.5_5kykwr4aqmxcvhhfl2j2qf3uya - '@ant-design/pro-form': 2.5.4_5kykwr4aqmxcvhhfl2j2qf3uya - '@ant-design/pro-provider': 2.4.0_5kykwr4aqmxcvhhfl2j2qf3uya - '@ant-design/pro-utils': 2.5.4_5kykwr4aqmxcvhhfl2j2qf3uya + '@ant-design/pro-card': 2.1.10_6pxft4cxqls2twurebs67c4zfy + '@ant-design/pro-field': 2.2.5_6pxft4cxqls2twurebs67c4zfy + '@ant-design/pro-form': 2.5.4_6pxft4cxqls2twurebs67c4zfy + '@ant-design/pro-provider': 2.4.0_6pxft4cxqls2twurebs67c4zfy + '@ant-design/pro-utils': 2.5.4_6pxft4cxqls2twurebs67c4zfy '@babel/runtime': 7.20.7 - antd: 5.1.5_biqbaboplfbrettd7655fr4n2y + antd: 5.1.6_biqbaboplfbrettd7655fr4n2y classnames: 2.3.2 dayjs: 1.11.5 omit.js: 2.0.2 @@ -696,7 +705,7 @@ packages: - '@types/lodash.merge' dev: false - /@ant-design/pro-utils/2.5.4_5kykwr4aqmxcvhhfl2j2qf3uya: + /@ant-design/pro-utils/2.5.4_6pxft4cxqls2twurebs67c4zfy: resolution: {integrity: sha512-fwnGRcYQbJwIyTWvioCw443qJ2Jq/TdkR/LFoewJqQK8zeZ7I62pEgLqxK0l0sffZpN1cKAIQfydqvcT3kl+mQ==} peerDependencies: antd: '>=4.23.0' @@ -704,9 +713,9 @@ packages: react-dom: '>=16.9.0' dependencies: '@ant-design/icons': 4.8.0_biqbaboplfbrettd7655fr4n2y - '@ant-design/pro-provider': 2.4.0_5kykwr4aqmxcvhhfl2j2qf3uya + '@ant-design/pro-provider': 2.4.0_6pxft4cxqls2twurebs67c4zfy '@babel/runtime': 7.20.7 - antd: 5.1.5_biqbaboplfbrettd7655fr4n2y + antd: 5.1.6_biqbaboplfbrettd7655fr4n2y classnames: 2.3.2 dayjs: 1.11.5 rc-util: 5.27.1_biqbaboplfbrettd7655fr4n2y @@ -5104,15 +5113,15 @@ packages: engines: {node: '>=12'} dev: true - /antd/5.1.5_biqbaboplfbrettd7655fr4n2y: - resolution: {integrity: sha512-f1gfmDG8CApTu1h6gtM7i/krMTP6WH55w7pUPAMHlp9jsviKR+ElPqSQeLZV3UjuxVNn0DWvGwWEJ0Rv/kbeEQ==} + /antd/5.1.6_biqbaboplfbrettd7655fr4n2y: + resolution: {integrity: sha512-9bn2B4rZ1c7IXtn5U95aNGJXmLOZyL1V5TiGq3pk3S3bGD13BA2eynSI//e3c2FAslZlqQlQEGV+NHms9ygAVA==} peerDependencies: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: '@ant-design/colors': 7.0.0 - '@ant-design/cssinjs': 1.5.0_biqbaboplfbrettd7655fr4n2y - '@ant-design/icons': 5.0.0_biqbaboplfbrettd7655fr4n2y + '@ant-design/cssinjs': 1.5.6_biqbaboplfbrettd7655fr4n2y + '@ant-design/icons': 5.0.1_biqbaboplfbrettd7655fr4n2y '@ant-design/react-slick': 1.0.0_react@18.2.0 '@babel/runtime': 7.20.7 '@ctrl/tinycolor': 3.4.1 @@ -5133,7 +5142,7 @@ packages: rc-input: 0.1.4_biqbaboplfbrettd7655fr4n2y rc-input-number: 7.4.0_biqbaboplfbrettd7655fr4n2y rc-mentions: 1.13.1_biqbaboplfbrettd7655fr4n2y - rc-menu: 9.8.0_biqbaboplfbrettd7655fr4n2y + rc-menu: 9.8.2_biqbaboplfbrettd7655fr4n2y rc-motion: 2.6.2_biqbaboplfbrettd7655fr4n2y rc-notification: 5.0.0_biqbaboplfbrettd7655fr4n2y rc-pagination: 3.2.0_biqbaboplfbrettd7655fr4n2y @@ -13293,7 +13302,7 @@ packages: dependencies: '@babel/runtime': 7.20.7 classnames: 2.3.2 - rc-menu: 9.8.0_biqbaboplfbrettd7655fr4n2y + rc-menu: 9.8.2_biqbaboplfbrettd7655fr4n2y rc-textarea: 0.4.6_biqbaboplfbrettd7655fr4n2y rc-trigger: 5.3.4_biqbaboplfbrettd7655fr4n2y rc-util: 5.27.1_biqbaboplfbrettd7655fr4n2y @@ -13318,8 +13327,8 @@ packages: shallowequal: 1.1.0 dev: true - /rc-menu/9.8.0_biqbaboplfbrettd7655fr4n2y: - resolution: {integrity: sha512-ftO5ExUMMSprzinxtHQz11KIRWY6P/tOs5ZexboWJ835LVQAMXuqDFqkjB/BXVC8WAKjj9t3eZmmweZp+guoYw==} + /rc-menu/9.8.2_biqbaboplfbrettd7655fr4n2y: + resolution: {integrity: sha512-EahOJVjLuEnJsThoPN+mGnVm431RzVzDLZWHRS/YnXTQULa7OsgdJa/Y7qXxc3Z5sz8mgT6xYtgpmBXLxrZFaQ==} peerDependencies: react: '>=16.9.0' react-dom: '>=16.9.0' @@ -13332,7 +13341,6 @@ packages: rc-util: 5.27.1_biqbaboplfbrettd7655fr4n2y react: 18.2.0 react-dom: 18.2.0_react@18.2.0 - shallowequal: 1.1.0 dev: false /rc-motion/2.6.2_biqbaboplfbrettd7655fr4n2y: @@ -13572,7 +13580,7 @@ packages: '@babel/runtime': 7.20.7 classnames: 2.3.2 rc-dropdown: 4.0.1_biqbaboplfbrettd7655fr4n2y - rc-menu: 9.8.0_biqbaboplfbrettd7655fr4n2y + rc-menu: 9.8.2_biqbaboplfbrettd7655fr4n2y rc-motion: 2.6.2_biqbaboplfbrettd7655fr4n2y rc-resize-observer: 1.2.0_biqbaboplfbrettd7655fr4n2y rc-util: 5.27.1_biqbaboplfbrettd7655fr4n2y From 5d22fdc5a53ba74078c9abf4311b653ff59cb6ad Mon Sep 17 00:00:00 2001 From: liulei Date: Sun, 22 Jan 2023 06:27:47 +0800 Subject: [PATCH 11/68] feat: celebrating Lunar New Year --- websites/workspace/src/App.tsx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/websites/workspace/src/App.tsx b/websites/workspace/src/App.tsx index c11d1b7..c390860 100644 --- a/websites/workspace/src/App.tsx +++ b/websites/workspace/src/App.tsx @@ -1,6 +1,6 @@ import { AppSpin } from '@/components' import { AppRouters } from '@/routers' -import { ConfigProvider } from 'antd' +import { ConfigProvider, Watermark } from 'antd' import zhCN from 'antd/locale/zh_CN' import { FC, Suspense } from 'react' import { BrowserRouter as Router } from 'react-router-dom' @@ -13,7 +13,14 @@ export const App: FC = () => { - + + + From aec5ca0588e8e1b285b4d2026b65f3ce71cc3346 Mon Sep 17 00:00:00 2001 From: liulei Date: Sun, 22 Jan 2023 06:37:11 +0800 Subject: [PATCH 12/68] fix(widget): initState type --- packages/core/src/widget/WidgetMetadata.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/core/src/widget/WidgetMetadata.ts b/packages/core/src/widget/WidgetMetadata.ts index 7a7b884..8d35004 100644 --- a/packages/core/src/widget/WidgetMetadata.ts +++ b/packages/core/src/widget/WidgetMetadata.ts @@ -103,7 +103,7 @@ export class WidgetMetadata< // TODO FIX TYPE this.setters = setters this.icon = icon - // TODO IMPORTMANT 完善类型定义 + // TODO IMPORTANT 完善类型定义 this.initState = ((...args: [{ id: string }]) => { const { id } = args[0] return { @@ -114,7 +114,9 @@ export class WidgetMetadata< }, ...(initState?.(...args) ?? {}), } - }) as unknown as typeof initState + }) as unknown as Required< + BaseWidgetMetadata + >['initState'] } version From 6705bb3ba80735cbec9f9236df2a12012733abda Mon Sep 17 00:00:00 2001 From: liulei Date: Sun, 22 Jan 2023 07:17:53 +0800 Subject: [PATCH 13/68] feat: remove Celebrating Lunar New Year --- websites/workspace/src/App.tsx | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/websites/workspace/src/App.tsx b/websites/workspace/src/App.tsx index c390860..c11d1b7 100644 --- a/websites/workspace/src/App.tsx +++ b/websites/workspace/src/App.tsx @@ -1,6 +1,6 @@ import { AppSpin } from '@/components' import { AppRouters } from '@/routers' -import { ConfigProvider, Watermark } from 'antd' +import { ConfigProvider } from 'antd' import zhCN from 'antd/locale/zh_CN' import { FC, Suspense } from 'react' import { BrowserRouter as Router } from 'react-router-dom' @@ -13,14 +13,7 @@ export const App: FC = () => { - - - + From 81ab34b3f9a796cd4b790f27e7cb1d92782ccef6 Mon Sep 17 00:00:00 2001 From: liulei Date: Sun, 22 Jan 2023 10:14:33 +0800 Subject: [PATCH 14/68] =?UTF-8?q?feat(widget):=20=E5=AE=8C=E5=96=84table?= =?UTF-8?q?=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/css-in-js/src/theme.tsx | 2 + packages/setters/src/components/number.tsx | 6 +- widgets/antd/package.json | 4 +- widgets/antd/src/TableWidget/index.tsx | 19 +- widgets/antd/src/TableWidget/metadata.tsx | 10 +- .../setters/ColumnsSetter/ColumnSetting.tsx | 168 ++++++++++++++++-- .../setters/ColumnsSetter/ColumnsSetter.tsx | 32 +++- widgets/antd/src/TableWidget/types.ts | 12 ++ 8 files changed, 220 insertions(+), 33 deletions(-) diff --git a/packages/css-in-js/src/theme.tsx b/packages/css-in-js/src/theme.tsx index 930cc30..dff7517 100644 --- a/packages/css-in-js/src/theme.tsx +++ b/packages/css-in-js/src/theme.tsx @@ -8,6 +8,7 @@ import { FC, ReactNode, useMemo } from 'react' interface MDTheme { colorPrimary: string colorError: string + colorText: string } interface ThemeProviderProps { @@ -21,6 +22,7 @@ export const ThemeProvider: FC = ({ children }) => { return { colorPrimary: token.colorPrimary, colorError: token.colorError, + colorText: token.colorText, } }, [token]) return {children} diff --git a/packages/setters/src/components/number.tsx b/packages/setters/src/components/number.tsx index e68968f..cd43e8c 100644 --- a/packages/setters/src/components/number.tsx +++ b/packages/setters/src/components/number.tsx @@ -20,6 +20,10 @@ type Props = BaseSetterProps export const NumberSetter: FC = ({ value, onChange }) => { return ( - onChange(val as number)} /> + onChange(val as number)} + style={{ width: '100%' }} + /> ) } diff --git a/widgets/antd/package.json b/widgets/antd/package.json index 17e67c2..0fc86a1 100644 --- a/widgets/antd/package.json +++ b/widgets/antd/package.json @@ -3,13 +3,13 @@ "version": "1.0.0", "description": "墨斗默认组件库", "scripts": { - "start": "npm run dev", + "start": "pnpm run dev", "dev": "dumi dev", "build": "father build", "build:watch": "father dev", "docs:build": "dumi build", "doctor": "father doctor", - "lint": "npm run lint:es && npm run lint:css", + "lint": "pnpm run lint:es && npm run lint:css", "lint:css": "stylelint \"{src,test}/**/*.{css,less}\"", "lint:es": "eslint \"{src,test}/**/*.{js,jsx,ts,tsx}\"", "prepublishOnly": "father doctor && npm run build" diff --git a/widgets/antd/src/TableWidget/index.tsx b/widgets/antd/src/TableWidget/index.tsx index ee01f7f..338c0b4 100644 --- a/widgets/antd/src/TableWidget/index.tsx +++ b/widgets/antd/src/TableWidget/index.tsx @@ -14,13 +14,22 @@ export const TableWidget: FC< }) const _columns: Array> = useMemo(() => { - return columns.map((c) => ({ - dataIndex: c.dataIndex, - title: c.title, - valueType: c.valueType, - })) + return columns.map((c, index) => { + const res: ProColumns = { + dataIndex: c.dataIndex, + title: c.title, + valueType: c.valueType, + align: c.align, + fixed: c.fixed ? c.fixed : false, + } + if (c.width > 0) { + res.width = c.width + 'px' + } + return res + }) }, [columns]) + console.log('_columns', _columns) return ( void }> = ({ children, value, onChange }) => { + const theme = useTheme() return ( - - - onChange( - produce(value, (draft) => { - draft.title = e.target.value - }), - ) - } - /> - - - ) : ( -
12123
- ) + {value.dataIndex}} + className={classes.wrapper} + style={{ color: theme.colorText }} + > +
+
+ + + onChange( + produce(value, (draft) => { + draft.title = e.target.value + }), + ) + } + /> + + + + onChange( + produce(value, (draft) => { + draft.align = e.target.value + }), + ) + } + value={value.align} + > + + + + + + + + + + + + + + + + + + + + onChange( + produce(value, (draft) => { + draft.fixed = e.target.value + }), + ) + } + value={value.fixed} + > + + + + + + + + + + + + + + + + + + + + onChange( + produce(value, (draft) => { + draft.width = v + }), + ) + } + /> + +
+
+
+ ) : null } > {children}
) } + +const classes = { + tooltipOverlay: mcss` + width: ${320 + 150}px; + max-width: 1000px; + padding-right: 150px; + `, + wrapper: mcss` + `, + + header: mcss` + `, + content: mcss` + .ant-form-item{ + margin-bottom: 12px; + } + .ant-radio-group{ + width: 100%; + display: flex; + .ant-radio-button-wrapper{ + flex: 1; + text-align: center; + } + } + `, + rotate_90: mcss` + transform: rotate(-90deg); + `, +} diff --git a/widgets/antd/src/TableWidget/setters/ColumnsSetter/ColumnsSetter.tsx b/widgets/antd/src/TableWidget/setters/ColumnsSetter/ColumnsSetter.tsx index 1b47f6c..c5ae86b 100644 --- a/widgets/antd/src/TableWidget/setters/ColumnsSetter/ColumnsSetter.tsx +++ b/widgets/antd/src/TableWidget/setters/ColumnsSetter/ColumnsSetter.tsx @@ -4,7 +4,7 @@ import { SettingOutlined, } from '@ant-design/icons' import { useMount, useUpdate } from 'ahooks' -import { Button, Form, Space, Table, Tooltip } from 'antd' +import { Button, Space, Table } from 'antd' import { ColumnsType } from 'antd/es/table' import produce from 'immer' import update from 'immutability-helper' @@ -22,17 +22,37 @@ import { generateId } from '@modou/core' import { mcss, useTheme } from '@modou/css-in-js' import { BaseSetterProps } from '@modou/setters' -import { ColumnValueTypeEnum } from '../../types' +import { + ColumnAlignEnum, + ColumnFixedEnum, + ColumnValueTypeEnum, +} from '../../types' import { ColumnSetting } from './ColumnSetting' import { DraggableBodyRow } from './DraggableBodyRow' import { TableWidgetColumn } from './types' -const generateDefaultColumn = (): TableWidgetColumn => { +const CUSTOM_COLUMN_DATA_INDEX_PREFIX = 'custom_column_' +const CUSTOM_COLUMN_TITLE_PREFIX = '自定义列-' +const NORMAL_WIDTH = -1 + +// TODO 从 mr 生成默认值 +const generateDefaultColumn = ( + columns: TableWidgetColumn[], +): TableWidgetColumn => { + const customColumns = columns.filter((c) => !c.buildIn) + const customColumnNumbers = customColumns.map( + (c) => +c.dataIndex.replace(CUSTOM_COLUMN_DATA_INDEX_PREFIX, ''), + ) + const maxCustomColumnNumber = + customColumnNumbers.length === 0 ? 1 : Math.max(...customColumnNumbers) + 1 return { - dataIndex: generateId(4), - title: '自定义列', + dataIndex: `${CUSTOM_COLUMN_DATA_INDEX_PREFIX}${maxCustomColumnNumber}`, + title: `${CUSTOM_COLUMN_TITLE_PREFIX}${maxCustomColumnNumber}`, valueType: ColumnValueTypeEnum.text, buildIn: false, + align: ColumnAlignEnum.left, + fixed: ColumnFixedEnum.false, + width: NORMAL_WIDTH, } } @@ -83,7 +103,7 @@ export const ColumnsSetter: FC> = ({ const [currentColumnIndex, setCurrentColumnIndex] = useState(0) const addColumn = () => { - onChange([...value, generateDefaultColumn()]) + onChange([...value, generateDefaultColumn(value)]) setCurrentColumnIndex(value.length) } const removeColumn = (index: number) => { diff --git a/widgets/antd/src/TableWidget/types.ts b/widgets/antd/src/TableWidget/types.ts index 1b86c59..6dfb34a 100644 --- a/widgets/antd/src/TableWidget/types.ts +++ b/widgets/antd/src/TableWidget/types.ts @@ -2,3 +2,15 @@ export enum ColumnValueTypeEnum { text = 'text', select = 'select', } + +export enum ColumnAlignEnum { + left = 'left', + center = 'center', + right = 'right', +} + +export enum ColumnFixedEnum { + left = 'left', + right = 'right', + false = '', +} From d6fae55f191c184d74265796afee2ac93c25f82f Mon Sep 17 00:00:00 2001 From: liulei Date: Sun, 22 Jan 2023 11:17:37 +0800 Subject: [PATCH 15/68] =?UTF-8?q?fix:=20=E7=A7=BB=E5=8A=A8=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E6=B5=8F=E8=A7=88=E5=99=A8=E5=B4=A9=E6=BA=83=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DesignerIndicator/indicatoir/SelectedIndicator.tsx | 2 +- .../components/DesignerIndicator/indicatoir/SelectedToolBox.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/SelectedIndicator.tsx b/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/SelectedIndicator.tsx index 554cc4d..769b751 100644 --- a/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/SelectedIndicator.tsx +++ b/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/SelectedIndicator.tsx @@ -102,7 +102,7 @@ const _SelectIndicatorContent: FC = () => { item: () => { return { type: WidgetDragType.Move, - widget, + widget: widget.meta, } }, collect: (monitor) => ({ diff --git a/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/SelectedToolBox.tsx b/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/SelectedToolBox.tsx index b02871e..71e2a05 100644 --- a/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/SelectedToolBox.tsx +++ b/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/SelectedToolBox.tsx @@ -28,7 +28,7 @@ const _SelectedToolBox: FC = () => { item: () => { return { type: WidgetDragType.Move, - widget, + widget: widget.meta, } }, collect: (monitor) => ({ From a53400f03e7ee1f6c21e70a38e15e55834d45af4 Mon Sep 17 00:00:00 2001 From: liulei Date: Sun, 22 Jan 2023 16:45:40 +0800 Subject: [PATCH 16/68] =?UTF-8?q?fix(designer):=20=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E6=8B=96=E6=8B=BD=E4=BA=A4=E6=8D=A2=E4=BD=8D=E7=BD=AE=E5=90=8E?= =?UTF-8?q?=E5=86=8D=E6=AC=A1=E6=8B=96=E6=8B=BD=E3=80=90=E4=BD=8D=E7=BD=AE?= =?UTF-8?q?=E6=8C=87=E7=A4=BA=E5=99=A8=E3=80=91=E6=98=BE=E7=A4=BA=E9=94=99?= =?UTF-8?q?=E4=B9=B1=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../indicatoir/DropIndicator.tsx | 63 +++++++++++++------ packages/reactivity-react/src/index.ts | 2 + packages/reactivity-react/src/useComputed.ts | 9 +++ .../render/src/components/WidgetVirtual.tsx | 63 +++++++++---------- 4 files changed, 87 insertions(+), 50 deletions(-) create mode 100644 packages/reactivity-react/src/useComputed.ts diff --git a/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/DropIndicator.tsx b/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/DropIndicator.tsx index 9225b24..fbd0a6d 100644 --- a/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/DropIndicator.tsx +++ b/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/DropIndicator.tsx @@ -1,18 +1,22 @@ -import { useMount, useMutationObserver } from 'ahooks' +import { useMemoizedFn, useMount, useMutationObserver } from 'ahooks' import { Col, Row, Typography } from 'antd' import { CSSProperties, FC, + ForwardRefRenderFunction, + forwardRef, useCallback, useContext, useEffect, + useImperativeHandle, useMemo, + useRef, useState, } from 'react' import { AppFactoryContext } from '@modou/core' import { mcss, useTheme } from '@modou/css-in-js' -import { observer } from '@modou/reactivity-react' +import { observer, useComputed } from '@modou/reactivity-react' import { SimulatorInstanceContext } from '../../../contexts' import { useCanvasDesignerFile } from '../../../contexts/CanvasDesignerFileContext' @@ -32,7 +36,14 @@ interface DropElement { slotPath: string } -const _WidgetDrop: FC = ({ widgetId, slotPath }) => { +interface WidgetDropInstance { + forceUpdateStyle: () => void +} + +const _WidgetDrop: ForwardRefRenderFunction = ( + { widgetId, slotPath }, + ref, +) => { const { canvasDesignerFile } = useCanvasDesignerFile() const { canvasDesignerStore } = useCanvasDesignerStore() const appFactory = useContext(AppFactoryContext) @@ -55,6 +66,9 @@ const _WidgetDrop: FC = ({ widgetId, slotPath }) => { }) const [styleUpdater, setStyleUpdater] = useState(0) + const forceUpdateStyle = useMemoizedFn(() => { + setStyleUpdater((prevState) => prevState + 1) + }) const { style } = useElementRect(element, { deps: [styleUpdater], }) @@ -63,12 +77,10 @@ const _WidgetDrop: FC = ({ widgetId, slotPath }) => { // void Promise.resolve().then(() => { // setStyleUpdater((prevState) => prevState + 1) // }) - setTimeout(() => { - setStyleUpdater((prevState) => prevState + 1) - }) - }, [canvasDesignerFile.widgets]) + setTimeout(forceUpdateStyle) + }, [canvasDesignerFile.widgets, forceUpdateStyle]) - const dropIndicatorStyle: CSSProperties = useMemo(() => { + const dropIndicatorStyle: CSSProperties = useComputed(() => { if (!canvasDesignerStore.dropIndicator.show) { return {} } @@ -105,15 +117,16 @@ const _WidgetDrop: FC = ({ widgetId, slotPath }) => { default: return {} } - }, [ - canvasDesignerStore.dropIndicator.position, - canvasDesignerStore.dropIndicator.show, - ]) + }) const theme = useTheme() const widgetMetadata = appFactory.widgetByType[widget.meta.type].metadata + useImperativeHandle(ref, () => ({ + forceUpdateStyle, + })) + return ( <> {isEmptySlot ? ( @@ -131,7 +144,10 @@ const _WidgetDrop: FC = ({ widgetId, slotPath }) => { ) : null} {isActive ? ( - +
= ({ widgetId, slotPath }) => { ) } -const WidgetDrop = observer(_WidgetDrop) +const WidgetDrop = observer(forwardRef(_WidgetDrop)) const widgetDropClasses = { emptyWrapper: mcss` border: 1px solid rgba(0,0,0,.1); @@ -173,6 +189,8 @@ const _DropIndicator: FC = () => { >([]) const simulatorInstance = useContext(SimulatorInstanceContext) + const widgetDropRef = useRef(null) + const initDrop = useCallback(() => { const elements = [ ...(simulatorInstance?.document?.querySelectorAll('[data-widget-id]') ?? @@ -188,10 +206,18 @@ const _DropIndicator: FC = () => { ) }, [simulatorInstance?.document]) useMount(initDrop) - useMutationObserver(initDrop, simulatorInstance.document?.body, { - childList: true, - subtree: true, - }) + useMutationObserver( + () => { + initDrop() + widgetDropRef.current?.forceUpdateStyle?.() + }, + simulatorInstance.document?.body, + { + childList: true, + subtree: true, + attributes: true, + }, + ) const dropElementsRendered = useMemo(() => { return dropElements.filter( ({ widgetId }) => canvasDesignerFile.widgetMap[widgetId], @@ -201,6 +227,7 @@ const _DropIndicator: FC = () => { <> {dropElementsRendered.map(({ widgetId, slotPath }) => ( (factory: () => T): T => { + return useLocalObservable(() => ({ + get value() { + return factory() + }, + })).value +} diff --git a/packages/render/src/components/WidgetVirtual.tsx b/packages/render/src/components/WidgetVirtual.tsx index bb5caba..cb95839 100644 --- a/packages/render/src/components/WidgetVirtual.tsx +++ b/packages/render/src/components/WidgetVirtual.tsx @@ -1,4 +1,4 @@ -import { mapValues, set } from 'lodash' +import { set } from 'lodash' import { FC, useContext, useEffect } from 'react' import * as React from 'react' @@ -10,7 +10,7 @@ import { runInAction, toJS, } from '@modou/reactivity' -import { observer, useLocalObservable } from '@modou/reactivity-react' +import { observer, useComputed } from '@modou/reactivity-react' import { WidgetState } from '@modou/state-manager' import { useStateManager } from '@modou/state-manager/src/contexts' @@ -33,34 +33,33 @@ const _WidgetVirtual: FC<{ const widgetDef = appFactory.widgetByType[widget.meta.type] // TODO any 替换 state 定义 const WidgetComponent = widgetDef.component - const localState = useLocalObservable(() => ({ - get renderSlots() { - return Object.entries(widgetDef.metadata.slots || {}) - .map(([slotPath, slot]) => { - return { - key: slotPath, - elements: widget.meta.slots[slotPath]?.map((widgetId) => ( - - )), - } - }) - .reduce>((pre, { key, elements }) => { - // FIXME 不知道为什么类型不对😂 - // pre[key] = elements - Reflect.set(pre, key, elements) - return pre - }, {}) - }, - get renderSlotPaths() { - return Object.keys(this.renderSlots).reduce>( - (pre, cur) => { - pre[cur] = cur - return pre - }, - {}, - ) - }, - })) + + const renderSlots = useComputed(() => { + return Object.entries(widgetDef.metadata.slots || {}) + .map(([slotPath, slot]) => { + return { + key: slotPath, + elements: widget.meta.slots[slotPath]?.map((widgetId) => ( + + )), + } + }) + .reduce>((pre, { key, elements }) => { + // FIXME 不知道为什么类型不对😂 + // pre[key] = elements + Reflect.set(pre, key, elements) + return pre + }, {}) + }) + const renderSlotPaths = useComputed(() => { + return Object.keys(renderSlots).reduce>( + (pre, cur) => { + pre[cur] = cur + return pre + }, + {}, + ) + }) useEffect(() => { const stopExps: IReactionDisposer[] = [] @@ -100,8 +99,8 @@ const _WidgetVirtual: FC<{ ) } From 23c0a2d12d103a6e9a6d44045f61214e156d4cc8 Mon Sep 17 00:00:00 2001 From: liulei Date: Sun, 22 Jan 2023 17:52:12 +0800 Subject: [PATCH 17/68] =?UTF-8?q?feat:=20meta-vfs=20=E6=8C=81=E4=B9=85?= =?UTF-8?q?=E5=8C=96=E5=AD=98=E5=82=A8=20&=20fix=20=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E6=8B=96=E6=8B=BD=E6=8C=87=E7=A4=BA=E5=99=A8=E4=BD=8D=E7=BD=AE?= =?UTF-8?q?=E6=B7=B7=E4=B9=B1=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/hooks/useElementRect.ts | 4 +- packages/meta-vfs/src/AppFile/index.ts | 44 +++++++++---------- packages/meta-vfs/src/EntityFile/index.ts | 6 +-- packages/meta-vfs/src/PageFile/index.ts | 3 +- .../src/features/app/routers/App.tsx | 9 +++- 5 files changed, 35 insertions(+), 31 deletions(-) diff --git a/packages/canvas-designer/src/hooks/useElementRect.ts b/packages/canvas-designer/src/hooks/useElementRect.ts index 6421e3f..b6409a5 100644 --- a/packages/canvas-designer/src/hooks/useElementRect.ts +++ b/packages/canvas-designer/src/hooks/useElementRect.ts @@ -27,7 +27,9 @@ export const useElementRect = ( width: rect.width, height: rect.height, }) - }, [element, ...(options.deps as any[])]) + // }, [element, ...(options.deps as any[])]) + // TODO 优化性能 + }) const style: CSSProperties = { width: `${elementRect.width ?? 0}px`, height: `${elementRect.height ?? 0}px`, diff --git a/packages/meta-vfs/src/AppFile/index.ts b/packages/meta-vfs/src/AppFile/index.ts index 1d1b900..c5b5360 100644 --- a/packages/meta-vfs/src/AppFile/index.ts +++ b/packages/meta-vfs/src/AppFile/index.ts @@ -1,5 +1,4 @@ import { isArray, keyBy } from 'lodash' -import { makePersistable } from 'mobx-persist-store' import { action, @@ -34,21 +33,18 @@ export class AppFile extends BaseFile { deleteEntity: action, deletePage: action, }) - void makePersistable(this, { - name: `${meta.id}`, - properties: [ - { - key: 'meta', - serialize: () => { - return this.toJSON() - }, - deserialize: () => { - return {} as unknown as AppFileMeta - }, - }, - ], - storage: window.localStorage, - }) + + if (typeof window !== 'undefined') { + window.addEventListener('visibilitychange', () => { + if (this.meta.id) { + window.localStorage.removeItem(this.meta.id) + window.localStorage.setItem( + this.meta.id, + JSON.stringify(this.toJSON()), + ) + } + }) + } } subFileMap: FileMap = { @@ -163,23 +159,27 @@ export class AppFile extends BaseFile { id: json.id, version: json.version, }) - const entities = json.entities.map((entity) => + json.entities.map((entity) => EntityFile.formJSON( entity as unknown as ReturnType, appFile, ), ) - const pages = json.pages.map((page) => + json.pages.map((page) => PageFile.formJSON( page as unknown as ReturnType, appFile, ), ) - runInAction(() => { - appFile.subFileMap.entities.push(...entities) - appFile.subFileMap.pages.push(...pages) - }) return appFile }) } + + static formLocal(appId: string) { + const appMeta = JSON.parse( + localStorage.getItem(appId) ?? '{}', + ) as unknown as ReturnType + console.log('appMetaappMeta', appMeta) + return this.formJSON(appMeta) + } } diff --git a/packages/meta-vfs/src/EntityFile/index.ts b/packages/meta-vfs/src/EntityFile/index.ts index 6946e78..4f3bca5 100644 --- a/packages/meta-vfs/src/EntityFile/index.ts +++ b/packages/meta-vfs/src/EntityFile/index.ts @@ -121,20 +121,18 @@ export class EntityFile extends BaseFile { omit(json, ['fileType', 'entityFields', 'entityRelations']), parentFile, ) - const entityFields = json.entityFields.map((entityField) => + json.entityFields.map((entityField) => EntityFieldFile.formJSON( entityField as unknown as ReturnType, entityFile, ), ) - const entityRelations = json.entityRelations.map((entityRelation) => + json.entityRelations.map((entityRelation) => EntityRelationFile.formJSON( entityRelation as unknown as ReturnType, entityFile, ), ) - entityFile.subFileMap.entityFields.push(...entityFields) - entityFile.subFileMap.entityRelations.push(...entityRelations) return entityFile }) } diff --git a/packages/meta-vfs/src/PageFile/index.ts b/packages/meta-vfs/src/PageFile/index.ts index 0336a64..2c2070f 100644 --- a/packages/meta-vfs/src/PageFile/index.ts +++ b/packages/meta-vfs/src/PageFile/index.ts @@ -259,13 +259,12 @@ export class PageFile extends BaseFile { omit(json, ['fileType', 'widgets']), parentFile, ) - const widgets = json.widgets.map((widget) => + json.widgets.map((widget) => WidgetFile.formJSON( widget as unknown as ReturnType, pageFile, ), ) - pageFile.subFileMap.widgets.push(...widgets) return pageFile }) } diff --git a/websites/workspace/src/features/app/routers/App.tsx b/websites/workspace/src/features/app/routers/App.tsx index 5702bc9..2ac29d4 100644 --- a/websites/workspace/src/features/app/routers/App.tsx +++ b/websites/workspace/src/features/app/routers/App.tsx @@ -15,7 +15,7 @@ import { import { AppManagerProvider } from '@modou/core' import { mcss } from '@modou/css-in-js' -import { AppManager } from '@modou/meta-vfs' +import { AppFile, AppManager } from '@modou/meta-vfs' import { runInAction } from '@modou/reactivity' import { ModuleManager } from '../components' @@ -38,8 +38,13 @@ const menuItems: ComponentProps['items'] = [ ] const appManager = runInAction(() => { - return new AppManager(mock_appFile) + try { + return new AppManager(AppFile.formLocal(mock_appFile.meta.id)) + } catch (e) { + return new AppManager(mock_appFile) + } }) + export const App: FC = () => { const params = useParams() const [module, setModule] = useState('') From 2d347183f9b3943677714f7d6c2cecbfa2074975 Mon Sep 17 00:00:00 2001 From: liulei Date: Sun, 22 Jan 2023 18:00:06 +0800 Subject: [PATCH 18/68] =?UTF-8?q?feat:=20=E8=A1=A8=E5=A4=B4=20=3D>=20=20?= =?UTF-8?q?=E8=A1=A8=E5=8D=95=E5=A4=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- widgets/antd/src/FormWidget/metadata.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/widgets/antd/src/FormWidget/metadata.tsx b/widgets/antd/src/FormWidget/metadata.tsx index 84dfaf4..802555d 100644 --- a/widgets/antd/src/FormWidget/metadata.tsx +++ b/widgets/antd/src/FormWidget/metadata.tsx @@ -46,12 +46,12 @@ export const formWidgetMetadata = WidgetMetadata.createMetadata< name: '表单', icon: , slots: { + header: { + name: '表单头', + }, children: { name: '默认插槽', }, - header: { - name: '表头', - }, }, setters: {}, mrPropsScheme: MRSchemeFormWidgetProps, From 80a7f8be8b447074465d22f5257d214f5a0c7626 Mon Sep 17 00:00:00 2001 From: liulei Date: Sun, 22 Jan 2023 18:53:30 +0800 Subject: [PATCH 19/68] =?UTF-8?q?fix(designer):=20=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E4=BD=8D=E7=BD=AE=E6=8B=96=E6=8B=BD=E6=B7=B7=E4=B9=B1=E5=92=8C?= =?UTF-8?q?=20move-after=E4=BD=8D=E7=BD=AE+1=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + .../src/components/CanvasDesignerOutlineTree.tsx | 6 +++++- .../DesignerIndicator/indicatoir/DropIndicator.tsx | 8 ++++++++ packages/canvas-designer/src/event-bus/index.ts | 9 +++++++++ packages/canvas-designer/src/hooks/useElementRect.ts | 5 ++--- packages/canvas-designer/src/hooks/useWidgetDrop.ts | 12 ++++++++---- packages/meta-vfs/src/AppFile/index.ts | 1 - pnpm-lock.yaml | 2 ++ widgets/antd/src/FormWidget/index.tsx | 6 ++++++ widgets/antd/src/FormWidget/metadata.tsx | 4 ++++ 10 files changed, 45 insertions(+), 9 deletions(-) create mode 100644 packages/canvas-designer/src/event-bus/index.ts diff --git a/package.json b/package.json index a98dfdf..e60dc34 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "immer": "^9.0.15", "immutability-helper": "^3.1.1", "lodash": "^4.17.21", + "mitt": "^3.0.0", "react": "^18.2.0", "react-dnd": "^16.0.1", "react-dnd-html5-backend": "^16.0.1", diff --git a/packages/canvas-designer/src/components/CanvasDesignerOutlineTree.tsx b/packages/canvas-designer/src/components/CanvasDesignerOutlineTree.tsx index 1dd36d0..1332916 100644 --- a/packages/canvas-designer/src/components/CanvasDesignerOutlineTree.tsx +++ b/packages/canvas-designer/src/components/CanvasDesignerOutlineTree.tsx @@ -12,6 +12,7 @@ import { observer } from '@modou/reactivity-react' import { useCanvasDesignerFile } from '../contexts/CanvasDesignerFileContext' import { useCanvasDesignerStore } from '../contexts/CanvasDesignerStoreContext' +import { emitter } from '../event-bus' import { OutlineTreeNode, OutlineTreeNodeSlot, @@ -83,7 +84,7 @@ const _CanvasDesignerOutlineTree: FC = () => { .with('slot', () => [ canvasDesignerFile.widgetMap[ (dropNode as unknown as OutlineTreeNodeSlot).slot.widgetId - ]?.meta!, + ]?.meta, (dropNode as unknown as OutlineTreeNodeSlot).slot.path, ]) .with('widget', () => [ @@ -133,6 +134,9 @@ const _CanvasDesignerOutlineTree: FC = () => { break default: } + setTimeout(() => { + emitter.emit('onWidgetElementChange') + }) } // TODO 支持大纲树和其画布及面板组件互相拖拽 IMPORTANT diff --git a/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/DropIndicator.tsx b/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/DropIndicator.tsx index fbd0a6d..7b6739a 100644 --- a/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/DropIndicator.tsx +++ b/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/DropIndicator.tsx @@ -21,6 +21,7 @@ import { observer, useComputed } from '@modou/reactivity-react' import { SimulatorInstanceContext } from '../../../contexts' import { useCanvasDesignerFile } from '../../../contexts/CanvasDesignerFileContext' import { useCanvasDesignerStore } from '../../../contexts/CanvasDesignerStoreContext' +import { emitter } from '../../../event-bus' import { useElementRect, useWidgetDrop } from '../../../hooks' import { DropIndicatorPositionEnum } from '../../../store' import { @@ -80,6 +81,13 @@ const _WidgetDrop: ForwardRefRenderFunction = ( setTimeout(forceUpdateStyle) }, [canvasDesignerFile.widgets, forceUpdateStyle]) + useEffect(() => { + emitter.on('onWidgetElementChange', forceUpdateStyle) + return () => { + emitter.off('onWidgetElementChange', forceUpdateStyle) + } + }) + const dropIndicatorStyle: CSSProperties = useComputed(() => { if (!canvasDesignerStore.dropIndicator.show) { return {} diff --git a/packages/canvas-designer/src/event-bus/index.ts b/packages/canvas-designer/src/event-bus/index.ts new file mode 100644 index 0000000..f4c51a8 --- /dev/null +++ b/packages/canvas-designer/src/event-bus/index.ts @@ -0,0 +1,9 @@ +import mitt from 'mitt' + +// eslint-disable-next-line @typescript-eslint/consistent-type-definitions +type Events = { + // eslint-disable-next-line @typescript-eslint/no-invalid-void-type + onWidgetElementChange: void +} + +export const emitter = mitt() diff --git a/packages/canvas-designer/src/hooks/useElementRect.ts b/packages/canvas-designer/src/hooks/useElementRect.ts index b6409a5..43c72ae 100644 --- a/packages/canvas-designer/src/hooks/useElementRect.ts +++ b/packages/canvas-designer/src/hooks/useElementRect.ts @@ -27,9 +27,8 @@ export const useElementRect = ( width: rect.width, height: rect.height, }) - // }, [element, ...(options.deps as any[])]) - // TODO 优化性能 - }) + }, [element, ...(options.deps as any[])]) + // }) const style: CSSProperties = { width: `${elementRect.width ?? 0}px`, height: `${elementRect.height ?? 0}px`, diff --git a/packages/canvas-designer/src/hooks/useWidgetDrop.ts b/packages/canvas-designer/src/hooks/useWidgetDrop.ts index 2e3374c..12c51ee 100644 --- a/packages/canvas-designer/src/hooks/useWidgetDrop.ts +++ b/packages/canvas-designer/src/hooks/useWidgetDrop.ts @@ -9,6 +9,7 @@ import { WidgetFileMeta } from '@modou/meta-vfs' import { useCanvasDesignerFile } from '../contexts/CanvasDesignerFileContext' import { useCanvasDesignerStore } from '../contexts/CanvasDesignerStoreContext' +import { emitter } from '../event-bus' import { DropIndicator, DropIndicatorInsertPositionEnum, @@ -186,10 +187,9 @@ export const useWidgetDrop = ({ sourceWidgetId: item.widget.id, targetWidgetId: parent.props.id, targetSlotPath: parentSlotPath, - targetPosition: - parent.props.slots[parentSlotPath].findIndex( - (widgetId) => widget.meta.id === widgetId, - ) + 1, + targetPosition: parent.props.slots[parentSlotPath].findIndex( + (widgetId) => widget.meta.id === widgetId, + ), }) } break @@ -241,6 +241,10 @@ export const useWidgetDrop = ({ default: } } + setTimeout(() => { + emitter.emit('onWidgetElementChange') + }) + return { widget: widget.meta } }, hover: (item, monitor) => { diff --git a/packages/meta-vfs/src/AppFile/index.ts b/packages/meta-vfs/src/AppFile/index.ts index c5b5360..7ec37ee 100644 --- a/packages/meta-vfs/src/AppFile/index.ts +++ b/packages/meta-vfs/src/AppFile/index.ts @@ -179,7 +179,6 @@ export class AppFile extends BaseFile { const appMeta = JSON.parse( localStorage.getItem(appId) ?? '{}', ) as unknown as ReturnType - console.log('appMetaappMeta', appMeta) return this.formJSON(appMeta) } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7349e71..2505fb6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -53,6 +53,7 @@ importers: immer: ^9.0.15 immutability-helper: ^3.1.1 lodash: ^4.17.21 + mitt: ^3.0.0 prettier: ^2.8.1 rc-tree: ^5.7.2 react: ^18.2.0 @@ -92,6 +93,7 @@ importers: immer: 9.0.15 immutability-helper: 3.1.1 lodash: 4.17.21 + mitt: 3.0.0 react: 18.2.0 react-dnd: 16.0.1_iapumuv4e6jcjznwuxpf4tt22e react-dnd-html5-backend: 16.0.1_kfajotxmcqjtgrepibrwmj5zwu diff --git a/widgets/antd/src/FormWidget/index.tsx b/widgets/antd/src/FormWidget/index.tsx index 3b774b0..5c2049d 100644 --- a/widgets/antd/src/FormWidget/index.tsx +++ b/widgets/antd/src/FormWidget/index.tsx @@ -50,6 +50,12 @@ export const FormWidget: FC< ))}
+
+ {renderSlots.footer} +
) } diff --git a/widgets/antd/src/FormWidget/metadata.tsx b/widgets/antd/src/FormWidget/metadata.tsx index 802555d..7aff51a 100644 --- a/widgets/antd/src/FormWidget/metadata.tsx +++ b/widgets/antd/src/FormWidget/metadata.tsx @@ -29,6 +29,7 @@ export const MRSchemeFormWidgetProps = WidgetMetadata.createMRWidgetProps({ slots: { children: mr.array(mr.string()).default([]), header: mr.array(mr.string()).default([]), + footer: mr.array(mr.string()).default([]), }, }) @@ -52,6 +53,9 @@ export const formWidgetMetadata = WidgetMetadata.createMetadata< children: { name: '默认插槽', }, + footer: { + name: '表单尾', + }, }, setters: {}, mrPropsScheme: MRSchemeFormWidgetProps, From 3cabaa6058f51d86a58d8ff2bcd4c7804d92eba4 Mon Sep 17 00:00:00 2001 From: liulei Date: Mon, 23 Jan 2023 09:05:31 +0800 Subject: [PATCH 20/68] =?UTF-8?q?fix(widget):=20formProText=20=E7=9B=B8?= =?UTF-8?q?=E5=90=8C=20name=20=E7=82=B9=E5=87=BB=20label=20=E4=BC=9A?= =?UTF-8?q?=E8=A7=A6=E5=8F=91=E5=A4=9A=E6=AC=A1=E7=82=B9=E5=87=BB=E4=BA=8B?= =?UTF-8?q?=E4=BB=B6=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/CanvasDesigner.tsx | 2 +- .../src/hooks/useWidgetSelected.ts | 6 ++++- .../app/components/ModuleManagerPage.tsx | 1 - websites/workspace/src/styles/index.css.ts | 5 ++++- widgets/antd/src/InputWidget/index.tsx | 17 +++++--------- widgets/antd/src/TableWidget/index.tsx | 10 ++++++--- .../setters/ColumnsSetter/ColumnSetting.tsx | 8 +++---- .../setters/ColumnsSetter/ColumnsSetter.tsx | 22 +++++++++---------- 8 files changed, 37 insertions(+), 34 deletions(-) diff --git a/packages/canvas-designer/src/components/CanvasDesigner.tsx b/packages/canvas-designer/src/components/CanvasDesigner.tsx index e7f51a2..85da889 100644 --- a/packages/canvas-designer/src/components/CanvasDesigner.tsx +++ b/packages/canvas-designer/src/components/CanvasDesigner.tsx @@ -1,4 +1,4 @@ -import { FC, ReactElement } from 'react' +import { FC, ReactElement, useEffect } from 'react' import { DndProvider } from 'react-dnd' import { HTML5Backend } from 'react-dnd-html5-backend' diff --git a/packages/canvas-designer/src/hooks/useWidgetSelected.ts b/packages/canvas-designer/src/hooks/useWidgetSelected.ts index 17d6647..079d545 100644 --- a/packages/canvas-designer/src/hooks/useWidgetSelected.ts +++ b/packages/canvas-designer/src/hooks/useWidgetSelected.ts @@ -9,11 +9,15 @@ export const useWidgetSelected = (canvasRef: RefObject) => { // TODO 由 select id 驱动 style useEventListener( 'click', - (event) => { + (event: MouseEvent) => { const rawElement = getSlotRawElement( event.target as unknown as HTMLElement, canvasRef.current, ) + // FIXME 下面代码解决 ProFormText 相同name点击事件会触发多次的问题 + if (event.offsetY < 0 || event.offsetX < 0) { + return + } const selectedWidgetId = getWidgetIdFromElement(rawElement as HTMLElement) canvasDesignerStore.setSelectedWidgetId(selectedWidgetId) }, diff --git a/websites/workspace/src/features/app/components/ModuleManagerPage.tsx b/websites/workspace/src/features/app/components/ModuleManagerPage.tsx index 7c554d7..cc9e39f 100644 --- a/websites/workspace/src/features/app/components/ModuleManagerPage.tsx +++ b/websites/workspace/src/features/app/components/ModuleManagerPage.tsx @@ -117,7 +117,6 @@ const _ModuleManagerPage: FC<{ onFinish={async (formData) => { await form.validateFields() console.log(formData) - // TODO 完善 addPage const rootWidgetId = generateId() const page = PageFile.create( { diff --git a/websites/workspace/src/styles/index.css.ts b/websites/workspace/src/styles/index.css.ts index 1de55ae..03e2b7c 100644 --- a/websites/workspace/src/styles/index.css.ts +++ b/websites/workspace/src/styles/index.css.ts @@ -12,12 +12,15 @@ injectGlobal` // 优化滚动条样式 injectGlobal` ::-webkit-scrollbar { - width: 4px; + width: 6px; + height: 6px; } /* 设置滚动条的背景颜色 */ ::-webkit-scrollbar-track { background: #f1f1f1; + width: 6px; + height: 6px; } /* 设置滚动条的滑块(滑轮)的颜色 */ diff --git a/widgets/antd/src/InputWidget/index.tsx b/widgets/antd/src/InputWidget/index.tsx index 5937b1f..59e7efa 100644 --- a/widgets/antd/src/InputWidget/index.tsx +++ b/widgets/antd/src/InputWidget/index.tsx @@ -1,4 +1,4 @@ -import { ProForm, ProFormText } from '@ant-design/pro-components' +import { ProFormText } from '@ant-design/pro-components' import { FC, useEffect } from 'react' import { InferWidgetState } from '../_' @@ -10,21 +10,16 @@ export const InputWidget: FC< useEffect(() => { console.log('我是Input 我重新渲染了') }) - useEffect(() => { - const hackElement = document.querySelector( - `[data-hack-widget-id=${instance.widgetId}]`, - ) - hackElement?.parentElement?.parentElement?.parentElement?.parentElement?.parentElement?.parentElement?.setAttribute( - 'data-widget-id', - instance.widgetId, - ) - }, [instance.widgetId]) return ( { console.log('onChange', e) diff --git a/widgets/antd/src/TableWidget/index.tsx b/widgets/antd/src/TableWidget/index.tsx index 338c0b4..1c9fabc 100644 --- a/widgets/antd/src/TableWidget/index.tsx +++ b/widgets/antd/src/TableWidget/index.tsx @@ -6,6 +6,8 @@ import { InferWidgetState } from '../_' import { MRSchemeTableWidgetState } from './metadata' import { MOCK_TABLE_DATA } from './mock' +const DEFAULT_COLUMN_WIDTH = 150 + export const TableWidget: FC< InferWidgetState > = ({ instance, renderSlots, renderSlotPaths, columns, size }) => { @@ -23,15 +25,17 @@ export const TableWidget: FC< fixed: c.fixed ? c.fixed : false, } if (c.width > 0) { - res.width = c.width + 'px' + res.width = c.width + } else { + c.width = DEFAULT_COLUMN_WIDTH } return res }) }, [columns]) - - console.log('_columns', _columns) + // FIXME 修改属性面板fixed需要刷新页面才会生效 return ( - + - + - + diff --git a/widgets/antd/src/TableWidget/setters/ColumnsSetter/ColumnsSetter.tsx b/widgets/antd/src/TableWidget/setters/ColumnsSetter/ColumnsSetter.tsx index c5ae86b..92130cf 100644 --- a/widgets/antd/src/TableWidget/setters/ColumnsSetter/ColumnsSetter.tsx +++ b/widgets/antd/src/TableWidget/setters/ColumnsSetter/ColumnsSetter.tsx @@ -3,7 +3,7 @@ import { HolderOutlined, SettingOutlined, } from '@ant-design/icons' -import { useMount, useUpdate } from 'ahooks' +import { useMemoizedFn, useMount, useUpdate } from 'ahooks' import { Button, Space, Table } from 'antd' import { ColumnsType } from 'antd/es/table' import produce from 'immer' @@ -20,6 +20,7 @@ import { createPortal } from 'react-dom' import { generateId } from '@modou/core' import { mcss, useTheme } from '@modou/css-in-js' +import { toJS } from '@modou/reactivity' import { BaseSetterProps } from '@modou/setters' import { @@ -79,7 +80,7 @@ export const ColumnsSetter: FC> = ({ (dragIndex: number, hoverIndex: number) => { const dragRow = value[dragIndex] onChange( - update(value, { + update(toJS(value), { $splice: [ [dragIndex, 1], [hoverIndex, 0, dragRow], @@ -119,16 +120,13 @@ export const ColumnsSetter: FC> = ({ } const currentColumn = value[currentColumnIndex] - const updateCurrentColumn = useCallback( - (newColumn: TableWidgetColumn) => { - onChange( - produce(value, (draft) => { - draft[currentColumnIndex] = newColumn - }), - ) - }, - [currentColumnIndex, onChange, value], - ) + const updateCurrentColumn = useMemoizedFn((newColumn: TableWidgetColumn) => { + onChange( + produce(toJS(value), (draft) => { + draft[currentColumnIndex] = newColumn + }), + ) + }) const columns: ColumnsType = [ { From 5aeb1b3a0867269efed1c13609f242ec9596fbee Mon Sep 17 00:00:00 2001 From: liulei Date: Mon, 23 Jan 2023 09:52:30 +0800 Subject: [PATCH 21/68] =?UTF-8?q?feat(render):=20=E4=BC=98=E5=8C=96=20stat?= =?UTF-8?q?e-manager=20=E8=84=9A=E6=9C=AC=E6=89=A7=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/meta-vfs/src/WidgetFile/index.ts | 4 +++- packages/render/src/components/ReactRender.tsx | 2 +- widgets/antd/src/TableWidget/index.tsx | 6 ++++++ widgets/antd/src/TableWidget/metadata.tsx | 1 + .../src/TableWidget/setters/ColumnsSetter/ColumnsSetter.tsx | 1 + 5 files changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/meta-vfs/src/WidgetFile/index.ts b/packages/meta-vfs/src/WidgetFile/index.ts index 8e57171..a75ceca 100644 --- a/packages/meta-vfs/src/WidgetFile/index.ts +++ b/packages/meta-vfs/src/WidgetFile/index.ts @@ -4,6 +4,7 @@ import { TextNode, baseParse, } from '@vue/compiler-core' +import { flatten } from 'flat' import { mapValues, omit } from 'lodash' import { WidgetBaseProps } from '@modou/core' @@ -13,6 +14,7 @@ import { makeObservable, observable, runInAction, + toJS, } from '@modou/reactivity' import { ParseNodeTypes } from '@modou/render/src/types' @@ -57,7 +59,7 @@ export class WidgetFile extends BaseFile<{}, WidgetFileMeta, PageFile> { get flattenedMetaValMap(): Record { return mapValues( - this.meta.props, + flatten(toJS(this.meta.props)), (value) => { if (isExpression(value)) { const ast = baseParse(value) diff --git a/packages/render/src/components/ReactRender.tsx b/packages/render/src/components/ReactRender.tsx index 2b02c45..2e7bcc9 100644 --- a/packages/render/src/components/ReactRender.tsx +++ b/packages/render/src/components/ReactRender.tsx @@ -1,6 +1,6 @@ import { ConfigProvider } from 'antd' import zhCN from 'antd/locale/zh_CN' -import { FC, useContext, useEffect } from 'react' +import { FC, useContext } from 'react' import * as React from 'react' import { AppFactoryContext, AppManagerProvider } from '@modou/core' diff --git a/widgets/antd/src/TableWidget/index.tsx b/widgets/antd/src/TableWidget/index.tsx index 1c9fabc..bb650fc 100644 --- a/widgets/antd/src/TableWidget/index.tsx +++ b/widgets/antd/src/TableWidget/index.tsx @@ -23,6 +23,9 @@ export const TableWidget: FC< valueType: c.valueType, align: c.align, fixed: c.fixed ? c.fixed : false, + render: () => { + return c.mappedValue || '-' + }, } if (c.width > 0) { res.width = c.width @@ -32,6 +35,9 @@ export const TableWidget: FC< return res }) }, [columns]) + + console.log('MOCK_TABLE_DATA.data', MOCK_TABLE_DATA.data) + // FIXME 修改属性面板fixed需要刷新页面才会生效 return ( Date: Mon, 23 Jan 2023 10:34:44 +0800 Subject: [PATCH 22/68] =?UTF-8?q?fix(state-manager):=20state=20=E5=92=8C?= =?UTF-8?q?=20file=20=E7=9A=84=E9=83=A8=E5=88=86=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E5=BC=95=E7=94=A8=E5=9C=B0=E5=9D=80=E4=B8=80=E6=A0=B7=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/state-manager/src/WidgetState/index.ts | 7 ++++--- .../setters/ColumnsSetter/ColumnSetting.tsx | 12 ++++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/packages/state-manager/src/WidgetState/index.ts b/packages/state-manager/src/WidgetState/index.ts index eefeed0..fec2b53 100644 --- a/packages/state-manager/src/WidgetState/index.ts +++ b/packages/state-manager/src/WidgetState/index.ts @@ -2,7 +2,7 @@ import { isFunction } from 'lodash' import { AppFactory } from '@modou/core' import { WidgetFile } from '@modou/meta-vfs' -import { makeAutoObservable } from '@modou/reactivity' +import { makeAutoObservable, toJS } from '@modou/reactivity' // TODO 完善类型定义 type BaseWidgetState = Record & { @@ -18,9 +18,10 @@ export class WidgetState { constructor(file: WidgetFile, appFactory: AppFactory) { const widgetDef = appFactory.widgetByType[file.meta.type] this.file = file + const rawMeta = toJS(file.meta) this.state = { - ...file.meta.props, - ...widgetDef.metadata.initState(file.meta), + ...toJS(rawMeta.props), + ...widgetDef.metadata.initState(rawMeta), } as unknown as BaseWidgetState makeAutoObservable(this) } diff --git a/widgets/antd/src/TableWidget/setters/ColumnsSetter/ColumnSetting.tsx b/widgets/antd/src/TableWidget/setters/ColumnsSetter/ColumnSetting.tsx index eec29d4..1227dfa 100644 --- a/widgets/antd/src/TableWidget/setters/ColumnsSetter/ColumnSetting.tsx +++ b/widgets/antd/src/TableWidget/setters/ColumnsSetter/ColumnSetting.tsx @@ -55,6 +55,18 @@ export const ColumnSetting: FC<{ } /> + + + onChange( + produce(value, (draft) => { + draft.mappedValue = e.target.value + }), + ) + } + /> + From a01830a4ac1c51ae8917086b51ff6a843a7f3dce Mon Sep 17 00:00:00 2001 From: liulei Date: Mon, 23 Jan 2023 14:17:11 +0800 Subject: [PATCH 23/68] =?UTF-8?q?feat(widget):=20table=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E8=87=AA=E5=AE=9A=E4=B9=89=E5=88=97=E6=B8=B2=E6=9F=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- widgets/antd/src/TableWidget/index.tsx | 4 +- .../setters/ColumnsSetter/ColumnSetting.tsx | 34 +++++++++- widgets/antd/src/TableWidget/types.ts | 64 +++++++++++++++++++ 3 files changed, 97 insertions(+), 5 deletions(-) diff --git a/widgets/antd/src/TableWidget/index.tsx b/widgets/antd/src/TableWidget/index.tsx index bb650fc..6663855 100644 --- a/widgets/antd/src/TableWidget/index.tsx +++ b/widgets/antd/src/TableWidget/index.tsx @@ -23,9 +23,7 @@ export const TableWidget: FC< valueType: c.valueType, align: c.align, fixed: c.fixed ? c.fixed : false, - render: () => { - return c.mappedValue || '-' - }, + renderText: () => c.mappedValue, } if (c.width > 0) { res.width = c.width diff --git a/widgets/antd/src/TableWidget/setters/ColumnsSetter/ColumnSetting.tsx b/widgets/antd/src/TableWidget/setters/ColumnsSetter/ColumnSetting.tsx index 1227dfa..3e71b35 100644 --- a/widgets/antd/src/TableWidget/setters/ColumnsSetter/ColumnSetting.tsx +++ b/widgets/antd/src/TableWidget/setters/ColumnsSetter/ColumnSetting.tsx @@ -4,14 +4,19 @@ import { VerticalAlignMiddleOutlined, VerticalAlignTopOutlined, } from '@ant-design/icons' -import { Card, Form, Input, Radio, Tooltip } from 'antd' +import { Card, Form, Input, Radio, Select, Tooltip } from 'antd' import produce from 'immer' import { FC, ReactElement } from 'react' import { mcss, useTheme } from '@modou/css-in-js' import { NumberSetter } from '@modou/setters' -import { ColumnAlignEnum, ColumnFixedEnum } from '../../types' +import { + ColumnAlignEnum, + ColumnFixedEnum, + ColumnValueTypeEnum, + ColumnValueTypeLabelMap, +} from '../../types' import { TableWidgetColumn } from './types' export const ColumnSetting: FC<{ @@ -55,6 +60,28 @@ export const ColumnSetting: FC<{ } /> + + + popupClassName={classes.selectPopup} + showSearch + value={value.valueType} + onChange={(v) => + onChange( + produce(value, (draft) => { + draft.valueType = v + }), + ) + } + > + {Object.entries(ColumnValueTypeLabelMap).map( + ([val, label]) => ( + + {label} + + ), + )} + + = { + password: '密码输入框', + money: '金额输入框', + textarea: '文本域', + date: '日期', + dateTime: '日期时间', + dateWeek: '周', + dateMonth: '月', + dateQuarter: '季度输入', + dateYear: '年份输入', + dateRange: '日期区间', + dateTimeRange: '日期时间区间', + time: '时间', + timeRange: '时间区间', + text: '文本框', + select: '下拉框', + treeSelect: '树形下拉框', + checkbox: '多选框', + rate: '星级组件', + radio: '单选框', + radioButton: '按钮单选框', + progress: '进度条', + percent: '百分比组件', + digit: '数字输入框', + second: '秒格式化', + avatar: '头像', + code: '代码框', + switch: '开关', + fromNow: '相对于当前时间', + image: '图片', + jsonCode: '代码框,但是带了 json 格式化', + color: '颜色选择器', + cascader: '级联选择器', } export enum ColumnAlignEnum { From f6d63f2c000916d82a2aab14e3ab3154e552d9e9 Mon Sep 17 00:00:00 2001 From: liulei Date: Mon, 23 Jan 2023 19:14:04 +0800 Subject: [PATCH 24/68] =?UTF-8?q?feat(widget):=20=E5=AE=8C=E5=96=84TableWi?= =?UTF-8?q?dget=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 3 + .../components/CanvasDesignerPropsPanel.tsx | 5 +- .../indicatoir/DropIndicator.tsx | 2 +- packages/core/src/widget/WidgetMetadata.ts | 2 +- packages/meta-vfs/src/WidgetFile/index.ts | 28 ++- .../render/src/components/WidgetVirtual.tsx | 10 +- .../state-manager/src/WidgetState/index.ts | 3 + pnpm-lock.yaml | 122 ++++++++++++- widgets/antd/src/TableWidget/index.tsx | 15 +- widgets/antd/src/TableWidget/metadata.tsx | 1 + .../setters/ColumnsSetter/ColumnSetting.tsx | 23 ++- .../setters/ColumnsSetter/ColumnsSetter.tsx | 172 ++++++++++++++---- .../setters/ColumnsSetter/utils/index.ts | 54 ++++++ 13 files changed, 367 insertions(+), 73 deletions(-) create mode 100644 widgets/antd/src/TableWidget/setters/ColumnsSetter/utils/index.ts diff --git a/package.json b/package.json index e60dc34..41673a5 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "@emotion/babel-plugin": "^11.10.5", "@trivago/prettier-plugin-sort-imports": "^3.3.1", "@types/flat": "^5.0.2", + "@types/json-schema": "^7.0.11", "@types/lodash": "^4.14.185", "@types/react": "^18.0.17", "@types/react-dom": "^18.0.6", @@ -60,8 +61,10 @@ "handlebars": "^4.7.7", "immer": "^9.0.15", "immutability-helper": "^3.1.1", + "json-schema": "^0.4.0", "lodash": "^4.17.21", "mitt": "^3.0.0", + "quicktype-core": "^21.0.2", "react": "^18.2.0", "react-dnd": "^16.0.1", "react-dnd-html5-backend": "^16.0.1", diff --git a/packages/canvas-designer/src/components/CanvasDesignerPropsPanel.tsx b/packages/canvas-designer/src/components/CanvasDesignerPropsPanel.tsx index c68ea94..15b7eb5 100644 --- a/packages/canvas-designer/src/components/CanvasDesignerPropsPanel.tsx +++ b/packages/canvas-designer/src/components/CanvasDesignerPropsPanel.tsx @@ -13,6 +13,7 @@ import { import { AppFactoryContext } from '@modou/core' import { cx, mcss } from '@modou/css-in-js' import { PageFileMeta, WidgetFileMeta } from '@modou/meta-vfs' +import { toJS } from '@modou/reactivity' import { observer } from '@modou/reactivity-react' import { SETTER_KEY } from '@modou/setters' import { SetterTypeEnum } from '@modou/setters/src/constants' @@ -48,7 +49,7 @@ const useRenderFormItem = ({ widgetId }: { widgetId: string }) => { > {NativeSetter ? ( { widget.updateMeta( produce((draft) => { @@ -60,7 +61,7 @@ const useRenderFormItem = ({ widgetId }: { widgetId: string }) => { ) : ( { widget.updateMeta( produce((draft) => { diff --git a/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/DropIndicator.tsx b/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/DropIndicator.tsx index 7b6739a..546265c 100644 --- a/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/DropIndicator.tsx +++ b/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/DropIndicator.tsx @@ -154,7 +154,7 @@ const _WidgetDrop: ForwardRefRenderFunction = ( {isActive ? (
{ (value) => { if (isExpression(value)) { const ast = baseParse(value) - return { - type: 'Expression', - raw: value, - ast, - evalString: `\`${ast.children + let evalString: string + if ( + ast.children.length === 1 && + // @ts-expect-error + head(ast.children)?.type === ParseNodeTypes.INTERPOLATION + ) { + evalString = + ( + (head(ast.children) as unknown as InterpolationNode) + ?.content as unknown as SimpleExpressionNode + ).content || '' + } else { + evalString = `\`${ast.children .map((item) => { // @ts-expect-error if (item.type === ParseNodeTypes.TEXT) { @@ -86,7 +94,13 @@ export class WidgetFile extends BaseFile<{}, WidgetFileMeta, PageFile> { // TODO 适配其他类型 return item.loc.source }) - .join('')}\``, + .join('')}\`` + } + return { + type: 'Expression', + raw: value, + ast, + evalString, } } else { return { diff --git a/packages/render/src/components/WidgetVirtual.tsx b/packages/render/src/components/WidgetVirtual.tsx index cb95839..b2826ef 100644 --- a/packages/render/src/components/WidgetVirtual.tsx +++ b/packages/render/src/components/WidgetVirtual.tsx @@ -70,7 +70,9 @@ const _WidgetVirtual: FC<{ Object.entries(value).forEach(([path, val]) => { if (val.type === 'Normal') { if (prev?.[path]?.raw !== val.raw) { - set(widgetState.state, path, val.raw) + runInAction(() => { + set(widgetState.state, path, val.raw) + }) } } else { stopExps.push( @@ -82,6 +84,8 @@ const _WidgetVirtual: FC<{ }), ) } + // TODO 如果是异步的 expression 如何处理 + widgetState.state.instance.initialized = true }) }, { @@ -95,13 +99,13 @@ const _WidgetVirtual: FC<{ // FIXME 会导致重新渲染 // FIXME 完善组件类型 - return ( + return widgetState.state.instance.initialized ? ( - ) + ) : null } export const WidgetVirtual = observer(_WidgetVirtual) diff --git a/packages/state-manager/src/WidgetState/index.ts b/packages/state-manager/src/WidgetState/index.ts index fec2b53..90c8001 100644 --- a/packages/state-manager/src/WidgetState/index.ts +++ b/packages/state-manager/src/WidgetState/index.ts @@ -19,8 +19,11 @@ export class WidgetState { const widgetDef = appFactory.widgetByType[file.meta.type] this.file = file const rawMeta = toJS(file.meta) + console.log('rawMeta', rawMeta) + // TODO 这个地方就要 eval this.state = { ...toJS(rawMeta.props), + // TODO initState 传递的参数应该是初始化的state 或者 计算后的 props ...widgetDef.metadata.initState(rawMeta), } as unknown as BaseWidgetState makeAutoObservable(this) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2505fb6..e4cd381 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -27,6 +27,7 @@ importers: '@recoiljs/refine': ^0.1.1 '@trivago/prettier-plugin-sort-imports': ^3.3.1 '@types/flat': ^5.0.2 + '@types/json-schema': ^7.0.11 '@types/lodash': ^4.14.185 '@types/react': ^18.0.17 '@types/react-dom': ^18.0.6 @@ -52,9 +53,11 @@ importers: handlebars: ^4.7.7 immer: ^9.0.15 immutability-helper: ^3.1.1 + json-schema: ^0.4.0 lodash: ^4.17.21 mitt: ^3.0.0 prettier: ^2.8.1 + quicktype-core: ^21.0.2 rc-tree: ^5.7.2 react: ^18.2.0 react-dnd: ^16.0.1 @@ -92,8 +95,10 @@ importers: handlebars: 4.7.7 immer: 9.0.15 immutability-helper: 3.1.1 + json-schema: 0.4.0 lodash: 4.17.21 mitt: 3.0.0 + quicktype-core: 21.0.2 react: 18.2.0 react-dnd: 16.0.1_iapumuv4e6jcjznwuxpf4tt22e react-dnd-html5-backend: 16.0.1_kfajotxmcqjtgrepibrwmj5zwu @@ -106,6 +111,7 @@ importers: '@emotion/babel-plugin': 11.10.5 '@trivago/prettier-plugin-sort-imports': 3.3.1_prettier@2.8.1 '@types/flat': 5.0.2 + '@types/json-schema': 7.0.11 '@types/lodash': 4.14.186 '@types/react': 18.0.21 '@types/react-dom': 18.0.6 @@ -2301,6 +2307,10 @@ packages: tslib: 2.4.0 dev: true + /@glideapps/ts-necessities/2.1.2: + resolution: {integrity: sha512-tLjfhinr6doUBcWi7BWnkT2zT6G5UhiZftsiIH6xVvykeXE+FU7Wr0MyqwmqideWlDD5rG+VjVLptLviGo04CA==} + dev: false + /@humanwhocodes/config-array/0.10.7: resolution: {integrity: sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w==} engines: {node: '>=10.10.0'} @@ -3744,6 +3754,10 @@ packages: resolution: {integrity: sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==} dev: true + /@types/urijs/1.19.19: + resolution: {integrity: sha512-FDJNkyhmKLw7uEvTxx5tSXfPeQpO0iy73Ry+PmYZJvQy0QIWX8a7kJ4kLWRf+EbTPJEPDSgPXHaM7pzr5lmvCg==} + dev: false + /@types/yargs-parser/21.0.0: resolution: {integrity: sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==} dev: true @@ -4913,6 +4927,13 @@ packages: through: 2.3.8 dev: true + /abort-controller/3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + dependencies: + event-target-shim: 5.0.1 + dev: false + /acorn-import-assertions/1.8.0_acorn@8.8.0: resolution: {integrity: sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==} peerDependencies: @@ -5510,7 +5531,6 @@ packages: /base64-js/1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - dev: true /big.js/5.2.2: resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==} @@ -5587,6 +5607,10 @@ packages: resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} dev: true + /browser-or-node/2.1.1: + resolution: {integrity: sha512-8CVjaLJGuSKMVTxJ2DpBl5XnlNDiT4cQFeuCJJrvJmts9YrTZDizTX7PjC2s6W4x+MBGZeEY6dGMrF04/6Hgqg==} + dev: false + /browserify-aes/1.2.0: resolution: {integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==} dependencies: @@ -5697,6 +5721,13 @@ packages: ieee754: 1.2.1 dev: true + /buffer/6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + dev: false + /builtin-status-codes/3.0.0: resolution: {integrity: sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==} dev: true @@ -6033,6 +6064,10 @@ packages: - supports-color dev: true + /collection-utils/1.0.1: + resolution: {integrity: sha512-LA2YTIlR7biSpXkKYwwuzGjwL5rjWEZVOSnvdUc7gObvWe4WkjxOpfrdhoP7Hs09YWDVfg0Mal9BpAqLfVEzQg==} + dev: false + /color-convert/1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} dependencies: @@ -8281,10 +8316,14 @@ packages: engines: {node: '>=0.10.0'} dev: true + /event-target-shim/5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} + dev: false + /events/3.3.0: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} - dev: true /evp_bytestokey/1.0.3: resolution: {integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==} @@ -9616,7 +9655,6 @@ packages: /ieee754/1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - dev: true /iferr/0.1.5: resolution: {integrity: sha512-DUNFN5j7Tln0D+TxzloUjKB+CtVu6myn0JEFak6dG18mNt9YkQ6lzGCdafwofISZ1lLF3xRHJ98VKy9ynkcFaA==} @@ -10103,6 +10141,10 @@ packages: engines: {node: '>=10'} dev: true + /is-url/1.2.4: + resolution: {integrity: sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==} + dev: false + /is-utf8/0.2.1: resolution: {integrity: sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==} dev: true @@ -10259,6 +10301,10 @@ packages: resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==} dev: true + /js-base64/2.6.4: + resolution: {integrity: sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==} + dev: false + /js-cookie/2.2.1: resolution: {integrity: sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==} dev: false @@ -10312,6 +10358,10 @@ packages: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} dev: true + /json-schema/0.4.0: + resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} + dev: false + /json-stable-stringify-without-jsonify/1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} dev: true @@ -11829,9 +11879,12 @@ packages: - supports-color dev: true + /pako/0.2.9: + resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==} + dev: false + /pako/1.0.11: resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} - dev: true /parallel-transform/1.2.0: resolution: {integrity: sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==} @@ -12054,7 +12107,6 @@ packages: /pluralize/8.0.0: resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} engines: {node: '>=4'} - dev: true /point-in-polygon/1.1.0: resolution: {integrity: sha512-3ojrFwjnnw8Q9242TzgXuTD+eKiutbzyslcq1ydfu82Db2y+Ogbmyrkpv0Hgj31qwT3lbS9+QAAO/pIQM35XRw==} @@ -12930,7 +12982,6 @@ packages: /process/0.11.10: resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} engines: {node: '>= 0.6.0'} - dev: true /promise-inflight/1.0.1_bluebird@3.7.2: resolution: {integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==} @@ -13088,6 +13139,28 @@ packages: engines: {node: '>=8'} dev: true + /quicktype-core/21.0.2: + resolution: {integrity: sha512-iNVLms/N+XsDQF/YfhAY2VKE5jSEkEOoRJUaZuyzjknB/1upT1fBtDU3+9o6bnFm1TD0B1WaEfA2kjl340h0lQ==} + dependencies: + '@glideapps/ts-necessities': 2.1.2 + '@types/urijs': 1.19.19 + browser-or-node: 2.1.1 + collection-utils: 1.0.1 + cross-fetch: 3.1.5 + is-url: 1.2.4 + js-base64: 2.6.4 + lodash: 4.17.21 + pako: 1.0.11 + pluralize: 8.0.0 + readable-stream: 4.3.0 + unicode-properties: 1.4.1 + urijs: 1.19.11 + wordwrap: 1.0.0 + yaml: 2.2.1 + transitivePeerDependencies: + - encoding + dev: false + /railroad-diagrams/1.0.0: resolution: {integrity: sha512-cz93DjNeLY0idrCNOH6PviZGRN9GJhsdm9hpn1YCS879fj4W+x5IFJhhkRZcwVgMmFF7R82UA/7Oh+R8lLZg6A==} dev: true @@ -14082,6 +14155,16 @@ packages: util-deprecate: 1.0.2 dev: true + /readable-stream/4.3.0: + resolution: {integrity: sha512-MuEnA0lbSi7JS8XM+WNJlWZkHAAdm7gETHdFK//Q/mChGyj2akEFtdLZh32jSdkWGbRwCW9pn6g3LWDdDeZnBQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + abort-controller: 3.0.0 + buffer: 6.0.3 + events: 3.3.0 + process: 0.11.10 + dev: false + /readdirp/3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} @@ -15376,6 +15459,10 @@ packages: setimmediate: 1.0.5 dev: true + /tiny-inflate/1.0.3: + resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==} + dev: false + /tinycolor2/1.4.2: resolution: {integrity: sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA==} dev: false @@ -15747,6 +15834,20 @@ packages: resolution: {integrity: sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==} dev: true + /unicode-properties/1.4.1: + resolution: {integrity: sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==} + dependencies: + base64-js: 1.5.1 + unicode-trie: 2.0.0 + dev: false + + /unicode-trie/2.0.0: + resolution: {integrity: sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==} + dependencies: + pako: 0.2.9 + tiny-inflate: 1.0.3 + dev: false + /unified/10.1.2: resolution: {integrity: sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==} dependencies: @@ -15879,6 +15980,10 @@ packages: punycode: 2.1.1 dev: true + /urijs/1.19.11: + resolution: {integrity: sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==} + dev: false + /url-parse-lax/1.0.0: resolution: {integrity: sha512-BVA4lR5PIviy2PMseNd2jbFQ+jwSwQGdJejf5ctd1rEXt0Ypd7yanUK9+lYechVlN5VaTJGsu2U/3MDDu6KgBA==} engines: {node: '>=0.10.0'} @@ -16342,6 +16447,11 @@ packages: engines: {node: '>= 14'} dev: true + /yaml/2.2.1: + resolution: {integrity: sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==} + engines: {node: '>= 14'} + dev: false + /yargs-parser/20.2.9: resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} engines: {node: '>=10'} diff --git a/widgets/antd/src/TableWidget/index.tsx b/widgets/antd/src/TableWidget/index.tsx index 6663855..42976ff 100644 --- a/widgets/antd/src/TableWidget/index.tsx +++ b/widgets/antd/src/TableWidget/index.tsx @@ -1,16 +1,16 @@ import { ProTable } from '@ant-design/pro-components' import type { ProColumns } from '@ant-design/pro-components' +import { isArray } from 'lodash' import { FC, useEffect, useMemo } from 'react' import { InferWidgetState } from '../_' import { MRSchemeTableWidgetState } from './metadata' -import { MOCK_TABLE_DATA } from './mock' const DEFAULT_COLUMN_WIDTH = 150 export const TableWidget: FC< InferWidgetState -> = ({ instance, renderSlots, renderSlotPaths, columns, size }) => { +> = ({ instance, renderSlots, renderSlotPaths, columns, size, dataSource }) => { useEffect(() => { console.log('我是Table 我重新渲染了', instance.widgetId) }) @@ -23,7 +23,12 @@ export const TableWidget: FC< valueType: c.valueType, align: c.align, fixed: c.fixed ? c.fixed : false, - renderText: () => c.mappedValue, + hideInTable: c.hideInTable, + // TODO ellipsis + // ellipsis: true, + } + if (c.mappedValue) { + res.renderText = () => c.mappedValue } if (c.width > 0) { res.width = c.width @@ -34,8 +39,6 @@ export const TableWidget: FC< }) }, [columns]) - console.log('MOCK_TABLE_DATA.data', MOCK_TABLE_DATA.data) - // FIXME 修改属性面板fixed需要刷新页面才会生效 return ( popupClassName={classes.selectPopup} showSearch + filterOption={(input, option) => { + return (`${option?.label}` ?? '') + .toLowerCase() + .includes(input.toLowerCase()) + }} + options={Object.entries(ColumnValueTypeLabelMap).map( + ([value, label]) => ({ + label, + value, + }), + )} value={value.valueType} onChange={(v) => onChange( @@ -72,15 +83,7 @@ export const ColumnSetting: FC<{ }), ) } - > - {Object.entries(ColumnValueTypeLabelMap).map( - ([val, label]) => ( - - {label} - - ), - )} - + /> { - const customColumns = columns.filter((c) => !c.buildIn) - const customColumnNumbers = customColumns.map( - (c) => +c.dataIndex.replace(CUSTOM_COLUMN_DATA_INDEX_PREFIX, ''), - ) - const maxCustomColumnNumber = - customColumnNumbers.length === 0 ? 1 : Math.max(...customColumnNumbers) + 1 - return { - dataIndex: `${CUSTOM_COLUMN_DATA_INDEX_PREFIX}${maxCustomColumnNumber}`, - title: `${CUSTOM_COLUMN_TITLE_PREFIX}${maxCustomColumnNumber}`, - valueType: ColumnValueTypeEnum.text, - buildIn: false, - align: ColumnAlignEnum.left, - fixed: ColumnFixedEnum.false, - width: NORMAL_WIDTH, - mappedValue: '开始-{{Math.random()}}-结束', - } +async function quicktypeJSON( + targetLanguage: string, + typeName: string, + jsonString: string, +) { + const jsonInput = jsonInputForTargetLanguage(targetLanguage) + + // We could add multiple samples for the same desired + // type, or many sources for other types. Here we're + // just making one type from one piece of sample JSON. + await jsonInput.addSource({ + name: typeName, + samples: [jsonString], + }) + + const inputData = new InputData() + inputData.addInput(jsonInput) + + return await quicktype({ + inputData, + lang: targetLanguage, + }) } export const ColumnsSetter: FC> = ({ @@ -81,7 +84,7 @@ export const ColumnsSetter: FC> = ({ (dragIndex: number, hoverIndex: number) => { const dragRow = value[dragIndex] onChange( - update(toJS(value), { + update(value, { $splice: [ [dragIndex, 1], [hoverIndex, 0, dragRow], @@ -123,7 +126,7 @@ export const ColumnsSetter: FC> = ({ const currentColumn = value[currentColumnIndex] const updateCurrentColumn = useMemoizedFn((newColumn: TableWidgetColumn) => { onChange( - produce(toJS(value), (draft) => { + produce(value, (draft) => { draft[currentColumnIndex] = newColumn }), ) @@ -156,21 +159,104 @@ export const ColumnsSetter: FC> = ({ dataIndex: 'operation', key: 'operation', align: 'center', - render: (value, record, index) => ( + render: (_value, record, index) => ( <> - + {!record.buildIn && ( + + )} + + {record.buildIn && ( + + )} ), }, ] + const testQuickTypeTest = useMemoizedFn(async () => { + const res = await quicktypeJSON( + 'JSON Schema', + 'Root', + JSON.stringify(MOCK_TABLE_DATA.data), + ) + const scheme: JSONSchema7 = JSON.parse(res.lines.join('\n')) + + const columns: TableWidgetColumn[] = [] + + const schemeRoot: JSONSchema7 = scheme.definitions! + .RootElement as unknown as JSONSchema7 + + const usedDataIndex = value.map((v) => v.dataIndex) + Object.entries(schemeRoot.properties!).forEach(([prop, scheme]) => { + // format [date-time, uri] + if (isBoolean(scheme)) { + return + } + if (usedDataIndex.includes(prop)) { + return + } + switch (scheme.type) { + case 'string': + case 'null': { + if (scheme.format === 'date-time') { + columns.push( + generateBuildInColumn({ + dataIndex: prop, + valueType: ColumnValueTypeEnum.dateTime, + }), + ) + } else { + columns.push( + generateBuildInColumn({ + dataIndex: prop, + valueType: ColumnValueTypeEnum.text, + }), + ) + } + break + } + case 'boolean': + columns.push( + generateBuildInColumn({ + dataIndex: prop, + valueType: ColumnValueTypeEnum.checkbox, + }), + ) + break + case 'integer': + columns.push( + generateBuildInColumn({ + dataIndex: prop, + valueType: ColumnValueTypeEnum.digit, + }), + ) + break + default: + } + }) + + onChange([...value, ...columns]) + }) + return (
> = ({ '--border-color': theme.colorPrimary, }} > + + {operationWrapper && createPortal( @@ -189,6 +277,8 @@ export const ColumnsSetter: FC> = ({ operationWrapper, )} + className={classes.table} + pagination={false} size={'small'} columns={columns} dataSource={dataSource} @@ -215,4 +305,12 @@ const classes = { border-top: 2px dashed var(--border-color); } `, + table: mcss` + tr.drop-over-downward td { + border-bottom: 2px dashed #1677ff !important; + } + tr.drop-over-upward td { + border-top: 2px dashed #1677ff !important; + } + `, } diff --git a/widgets/antd/src/TableWidget/setters/ColumnsSetter/utils/index.ts b/widgets/antd/src/TableWidget/setters/ColumnsSetter/utils/index.ts new file mode 100644 index 0000000..fad07a3 --- /dev/null +++ b/widgets/antd/src/TableWidget/setters/ColumnsSetter/utils/index.ts @@ -0,0 +1,54 @@ +import { + ColumnAlignEnum, + ColumnFixedEnum, + ColumnValueTypeEnum, +} from '../../../types' +import { TableWidgetColumn } from '../types' + +const CUSTOM_COLUMN_DATA_INDEX_PREFIX = 'custom_column_' +const CUSTOM_COLUMN_TITLE_PREFIX = '自定义列-' +const NORMAL_WIDTH = -1 +// TODO 从 mr 生成默认值 +export const generateDefaultColumn = ( + columns: TableWidgetColumn[], +): TableWidgetColumn => { + const customColumns = columns.filter((c) => !c.buildIn) + const customColumnNumbers = customColumns.map( + (c) => +c.dataIndex.replace(CUSTOM_COLUMN_DATA_INDEX_PREFIX, ''), + ) + const maxCustomColumnNumber = + customColumnNumbers.length === 0 ? 1 : Math.max(...customColumnNumbers) + 1 + return { + dataIndex: `${CUSTOM_COLUMN_DATA_INDEX_PREFIX}${maxCustomColumnNumber}`, + title: `${CUSTOM_COLUMN_TITLE_PREFIX}${maxCustomColumnNumber}`, + valueType: ColumnValueTypeEnum.text, + buildIn: false, + align: ColumnAlignEnum.left, + fixed: ColumnFixedEnum.false, + width: NORMAL_WIDTH, + mappedValue: '开始-{{Math.random()}}-结束', + hideInTable: false, + } +} +// TODO 从 mr 生成 默认值 +export const generateBuildInColumn = ({ + dataIndex, + valueType, + title, +}: { + dataIndex: string + valueType: ColumnValueTypeEnum + title?: string +}): TableWidgetColumn => { + return { + dataIndex, + title: title ?? dataIndex, + valueType, + buildIn: true, + align: ColumnAlignEnum.left, + fixed: ColumnFixedEnum.false, + width: NORMAL_WIDTH, + mappedValue: null, + hideInTable: false, + } +} From ceaaf3baf27918ca1d93f9d8ce42ba50e67c2673 Mon Sep 17 00:00:00 2001 From: liulei Date: Mon, 23 Jan 2023 19:19:19 +0800 Subject: [PATCH 25/68] =?UTF-8?q?feat(widget):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E8=A1=A8=E6=A0=BC=E5=88=97=E6=8B=96=E6=8B=BD=E7=A7=BB=E5=8A=A8?= =?UTF-8?q?=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../setters/ColumnsSetter/ColumnsSetter.tsx | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/widgets/antd/src/TableWidget/setters/ColumnsSetter/ColumnsSetter.tsx b/widgets/antd/src/TableWidget/setters/ColumnsSetter/ColumnsSetter.tsx index 8826ad8..706dbc4 100644 --- a/widgets/antd/src/TableWidget/setters/ColumnsSetter/ColumnsSetter.tsx +++ b/widgets/antd/src/TableWidget/setters/ColumnsSetter/ColumnsSetter.tsx @@ -277,7 +277,6 @@ export const ColumnsSetter: FC> = ({ operationWrapper, )} - className={classes.table} pagination={false} size={'small'} columns={columns} @@ -298,19 +297,11 @@ export const ColumnsSetter: FC> = ({ const classes = { wrapper: mcss` .ant-table tr.drop-over-downward td { - border-bottom: 2px dashed var(--border-color); + border-bottom: 2px dashed var(--border-color) !important; } .ant-table tr.drop-over-upward td { - border-top: 2px dashed var(--border-color); + border-top: 2px dashed var(--border-color) !important; } `, - table: mcss` - tr.drop-over-downward td { - border-bottom: 2px dashed #1677ff !important; - } - tr.drop-over-upward td { - border-top: 2px dashed #1677ff !important; - } - `, } From 0fb2e76b51cde6f88c04e48810f93b4acf547988 Mon Sep 17 00:00:00 2001 From: liulei Date: Mon, 23 Jan 2023 21:02:27 +0800 Subject: [PATCH 26/68] =?UTF-8?q?fix(widget):=20table=20=E5=88=97=20?= =?UTF-8?q?=E6=97=A0=E6=B3=95=E5=88=A0=E9=99=A4=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/reactivity/src/index.ts | 1 + .../render/src/components/WidgetVirtual.tsx | 23 +++++++++++- widgets/antd/src/TableWidget/index.tsx | 36 ++++++++++--------- 3 files changed, 42 insertions(+), 18 deletions(-) diff --git a/packages/reactivity/src/index.ts b/packages/reactivity/src/index.ts index 3dfc8c5..9e31192 100644 --- a/packages/reactivity/src/index.ts +++ b/packages/reactivity/src/index.ts @@ -21,6 +21,7 @@ export const makeObservable = mobx.makeObservable export const observable = mobx.observable export const observe = mobx.observe export const reaction = mobx.reaction +export const remove = mobx.remove export const runInAction = mobx.runInAction export const set = mobx.set export const toJS = mobx.toJS diff --git a/packages/render/src/components/WidgetVirtual.tsx b/packages/render/src/components/WidgetVirtual.tsx index b2826ef..0e07662 100644 --- a/packages/render/src/components/WidgetVirtual.tsx +++ b/packages/render/src/components/WidgetVirtual.tsx @@ -1,4 +1,4 @@ -import { set } from 'lodash' +import { get, head, isNumber, omit, set, take, takeRight, unset } from 'lodash' import { FC, useContext, useEffect } from 'react' import * as React from 'react' @@ -7,6 +7,7 @@ import { IReactionDisposer, autorun, reaction, + remove, runInAction, toJS, } from '@modou/reactivity' @@ -67,6 +68,26 @@ const _WidgetVirtual: FC<{ () => widgetState.file.flattenedMetaValMap, (value, prev) => { stopExps.forEach((stop) => stop()) + const omitPaths = Object.keys(omit(prev, Object.keys(value))) + // 处理 数组 类型的 state 在props删除后不会更新的问题 + // 比如 {columns:[{a:1},{a:2}]} => {columns:[{a:1}]} + runInAction(() => { + if (omitPaths.length > 0) { + omitPaths.forEach((path) => { + unset(widgetState.state, path) + const pathArr = path.split('.') + // TODO 需要更加准确的判断需要删除的数组路径 + if (isNumber(+pathArr[pathArr.length - 2])) { + remove( + get(widgetState.state, take(pathArr, pathArr.length - 2)), + head(takeRight(pathArr, 2)), + ) + } + }) + } + console.log('widgetState.state', widgetState.state) + }) + // TODO 如果state是数组的时候如何删除多余的数组 Object.entries(value).forEach(([path, val]) => { if (val.type === 'Normal') { if (prev?.[path]?.raw !== val.raw) { diff --git a/widgets/antd/src/TableWidget/index.tsx b/widgets/antd/src/TableWidget/index.tsx index 42976ff..d54e3f1 100644 --- a/widgets/antd/src/TableWidget/index.tsx +++ b/widgets/antd/src/TableWidget/index.tsx @@ -41,23 +41,25 @@ export const TableWidget: FC< // FIXME 修改属性面板fixed需要刷新页面才会生效 return ( - +
+ +
) } From ea1b2c66a9bb9650e8e4b8fe68ecc79ffb5b18d1 Mon Sep 17 00:00:00 2001 From: liulei Date: Mon, 23 Jan 2023 21:37:31 +0800 Subject: [PATCH 27/68] =?UTF-8?q?fix(render):=20props=20=E9=A9=B1=E5=8A=A8?= =?UTF-8?q?=20state=20=E6=95=B0=E7=BB=84=E6=9C=AA=E8=83=BD=E5=AF=B9?= =?UTF-8?q?=E9=BD=90=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/render/src/components/WidgetVirtual.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/render/src/components/WidgetVirtual.tsx b/packages/render/src/components/WidgetVirtual.tsx index 0e07662..4a9e3c5 100644 --- a/packages/render/src/components/WidgetVirtual.tsx +++ b/packages/render/src/components/WidgetVirtual.tsx @@ -68,7 +68,12 @@ const _WidgetVirtual: FC<{ () => widgetState.file.flattenedMetaValMap, (value, prev) => { stopExps.forEach((stop) => stop()) - const omitPaths = Object.keys(omit(prev, Object.keys(value))) + // TODO 需要更加准确的判断需要删除的数组路径 + const newValPaths = Object.keys(value) + const newValHeadPath = newValPaths.map((path) => head(path.split('.'))) + const omitPaths = Object.keys(omit(prev, newValPaths)).filter( + (path) => !newValHeadPath.includes(path), + ) // 处理 数组 类型的 state 在props删除后不会更新的问题 // 比如 {columns:[{a:1},{a:2}]} => {columns:[{a:1}]} runInAction(() => { From c10c2fb58500494b4ad399e36d1354546730418b Mon Sep 17 00:00:00 2001 From: liulei Date: Mon, 23 Jan 2023 23:06:21 +0800 Subject: [PATCH 28/68] fix(widget): tableWidget width init --- .../canvas-designer/src/components/CanvasDesignerCanvas.tsx | 3 +++ packages/render/src/components/ReactRenderTolerant.tsx | 1 - widgets/antd/src/TableWidget/index.tsx | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/canvas-designer/src/components/CanvasDesignerCanvas.tsx b/packages/canvas-designer/src/components/CanvasDesignerCanvas.tsx index dace003..025c3bb 100644 --- a/packages/canvas-designer/src/components/CanvasDesignerCanvas.tsx +++ b/packages/canvas-designer/src/components/CanvasDesignerCanvas.tsx @@ -103,8 +103,11 @@ const classes = { spinWrapper: mcss` height: 100%; width: 100%; + top: 0; + left: 0; display: flex; justify-content: center; align-items: center; + position: absolute; `, } diff --git a/packages/render/src/components/ReactRenderTolerant.tsx b/packages/render/src/components/ReactRenderTolerant.tsx index 72a5b34..a5fe2b2 100644 --- a/packages/render/src/components/ReactRenderTolerant.tsx +++ b/packages/render/src/components/ReactRenderTolerant.tsx @@ -4,7 +4,6 @@ import * as React from 'react' import { useAppManager } from '@modou/core' import { mcss } from '@modou/css-in-js' -import { trace } from '@modou/reactivity' import { observer } from '@modou/reactivity-react' import { useCanvasFile } from '../contexts' diff --git a/widgets/antd/src/TableWidget/index.tsx b/widgets/antd/src/TableWidget/index.tsx index d54e3f1..56750c5 100644 --- a/widgets/antd/src/TableWidget/index.tsx +++ b/widgets/antd/src/TableWidget/index.tsx @@ -33,7 +33,7 @@ export const TableWidget: FC< if (c.width > 0) { res.width = c.width } else { - c.width = DEFAULT_COLUMN_WIDTH + res.width = DEFAULT_COLUMN_WIDTH } return res }) From 5e0c95ac63596a6eebc97fb728ea7a179fa9b344 Mon Sep 17 00:00:00 2001 From: liulei Date: Tue, 24 Jan 2023 21:24:42 +0800 Subject: [PATCH 29/68] =?UTF-8?q?feat(widget):=20=E5=A2=9E=E5=8A=A0dynamic?= =?UTF-8?q?Slots?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/CanvasDesignerPropsPanel.tsx | 1 + .../indicatoir/DropIndicator.tsx | 5 ++-- .../indicatoir/SelectedToolBox.tsx | 5 +++- packages/core/src/widget/WidgetMetadata.ts | 14 +++++++++-- packages/refine/src/index.ts | 2 +- .../parsers/parseObject.ts | 3 +++ .../render/src/components/WidgetVirtual.tsx | 9 +++---- packages/setters/src/types/index.ts | 7 ++++++ .../state-manager/src/WidgetState/index.ts | 4 ++-- widgets/antd/src/TableWidget/index.tsx | 24 +++++++++++++++---- widgets/antd/src/TableWidget/metadata.tsx | 9 ++++++- .../setters/ColumnsSetter/ColumnsSetter.tsx | 5 ++-- 12 files changed, 68 insertions(+), 20 deletions(-) diff --git a/packages/canvas-designer/src/components/CanvasDesignerPropsPanel.tsx b/packages/canvas-designer/src/components/CanvasDesignerPropsPanel.tsx index 15b7eb5..b702c6e 100644 --- a/packages/canvas-designer/src/components/CanvasDesignerPropsPanel.tsx +++ b/packages/canvas-designer/src/components/CanvasDesignerPropsPanel.tsx @@ -49,6 +49,7 @@ const useRenderFormItem = ({ widgetId }: { widgetId: string }) => { > {NativeSetter ? ( { widget.updateMeta( diff --git a/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/DropIndicator.tsx b/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/DropIndicator.tsx index 546265c..9acc22f 100644 --- a/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/DropIndicator.tsx +++ b/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/DropIndicator.tsx @@ -233,10 +233,11 @@ const _DropIndicator: FC = () => { }, [canvasDesignerFile.widgetMap, dropElements]) return ( <> - {dropElementsRendered.map(({ widgetId, slotPath }) => ( + {dropElementsRendered.map(({ widgetId, slotPath }, index) => ( diff --git a/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/SelectedToolBox.tsx b/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/SelectedToolBox.tsx index 71e2a05..0b9f79b 100644 --- a/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/SelectedToolBox.tsx +++ b/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/SelectedToolBox.tsx @@ -93,11 +93,14 @@ const _SelectedToolBox: FC = () => { icon={} /> + {/* + */}
) diff --git a/packages/core/src/widget/WidgetMetadata.ts b/packages/core/src/widget/WidgetMetadata.ts index 462c382..457fab3 100644 --- a/packages/core/src/widget/WidgetMetadata.ts +++ b/packages/core/src/widget/WidgetMetadata.ts @@ -19,6 +19,7 @@ import { MRStringSetterType, SETTER_KEY, } from '@modou/setters' +import { BaseWidgetSetterProps } from '@modou/setters/src/types' import { InferWidgetState } from '@modou/widgets-antd' import { MDVersion } from '../types' @@ -43,7 +44,7 @@ interface BaseWidgetMetadata< name: string slots: WidgetSlots // TODO FIX TYPE - setters: Record>> + setters: Record>> mrPropsScheme: PropsMRScheme mrStateScheme: StateMRScheme // TODO 通过 props 和 state 的类型对比判断 initState 是否是必传的 @@ -129,7 +130,7 @@ export class WidgetMetadata< jsonStateSchema: JsonSchema7ObjectType initState slots: WidgetSlots - setters: Record>> + setters: Record>> static createMetadata< PropsMRScheme extends MRScheme, @@ -175,6 +176,15 @@ export class WidgetMetadata< name: mr.literal(name), props: mr.object(propsRawShape), slots: mr.object(slots ?? ({} as unknown as S)), + dynamicSlots: mr + .record( + mr.object({ + name: mr.string(), + children: mr.array(mr.string()), + accept: mr.array(mr.string()).optional(), + }), + ) + .default({}), }) } diff --git a/packages/refine/src/index.ts b/packages/refine/src/index.ts index 5c5032c..af4f42c 100644 --- a/packages/refine/src/index.ts +++ b/packages/refine/src/index.ts @@ -7,7 +7,7 @@ import type { ZodType, ZodTypeAny, } from '@lowcode-modou/zod' -import { ZodObject } from '@lowcode-modou/zod' +import { ZodObject, ZodRecord } from '@lowcode-modou/zod' import { name, version } from '../package.json' diff --git a/packages/refine/src/scheme-to-json-default/parsers/parseObject.ts b/packages/refine/src/scheme-to-json-default/parsers/parseObject.ts index f7114e7..f301fbf 100644 --- a/packages/refine/src/scheme-to-json-default/parsers/parseObject.ts +++ b/packages/refine/src/scheme-to-json-default/parsers/parseObject.ts @@ -12,6 +12,9 @@ export const parseObject = ( ) ? cloneDeep(schema.default!) : DEFAULT_TO_EMPTY + if (!schema.properties) { + return {} + } Object.entries(schema.properties).forEach(([key, value]) => { const defaultItem = parseScheme(value) if (defaultItem === DEFAULT_TO_EMPTY) { diff --git a/packages/render/src/components/WidgetVirtual.tsx b/packages/render/src/components/WidgetVirtual.tsx index 4a9e3c5..254f5cf 100644 --- a/packages/render/src/components/WidgetVirtual.tsx +++ b/packages/render/src/components/WidgetVirtual.tsx @@ -69,15 +69,17 @@ const _WidgetVirtual: FC<{ (value, prev) => { stopExps.forEach((stop) => stop()) // TODO 需要更加准确的判断需要删除的数组路径 + // 处理 数组 类型的 state 在props删除后不会更新的问题 + // 比如 {columns:[{a:1},{a:2}]} => {columns:[{a:1}]} state 的第一项并不会删除 const newValPaths = Object.keys(value) const newValHeadPath = newValPaths.map((path) => head(path.split('.'))) const omitPaths = Object.keys(omit(prev, newValPaths)).filter( (path) => !newValHeadPath.includes(path), ) - // 处理 数组 类型的 state 在props删除后不会更新的问题 - // 比如 {columns:[{a:1},{a:2}]} => {columns:[{a:1}]} runInAction(() => { if (omitPaths.length > 0) { + // 处理 数组 类型的 state 在props删除后不会更新的问题 + // 比如 {columns:[{a:1},{a:2}]} => {columns:[{a:1}]} state 的第一项并不会删除 omitPaths.forEach((path) => { unset(widgetState.state, path) const pathArr = path.split('.') @@ -90,7 +92,6 @@ const _WidgetVirtual: FC<{ } }) } - console.log('widgetState.state', widgetState.state) }) // TODO 如果state是数组的时候如何删除多余的数组 Object.entries(value).forEach(([path, val]) => { @@ -123,7 +124,7 @@ const _WidgetVirtual: FC<{ } }, []) - // FIXME 会导致重新渲染 + console.log('widgetState.state', widgetState.state) // FIXME 完善组件类型 return widgetState.state.instance.initialized ? ( { options?: O } +export interface BaseWidgetSetterProps + extends BaseSetterProps { + // TODO widget meta + widget: WidgetFile +} + export interface BaseMRSetterOptions { label: string description?: string diff --git a/packages/state-manager/src/WidgetState/index.ts b/packages/state-manager/src/WidgetState/index.ts index 90c8001..c410574 100644 --- a/packages/state-manager/src/WidgetState/index.ts +++ b/packages/state-manager/src/WidgetState/index.ts @@ -34,9 +34,9 @@ export class WidgetState { // TODO 完善 Widget State 定义 state: BaseWidgetState - updateState( + updateState = ( state: BaseWidgetState | ((oldState: BaseWidgetState) => BaseWidgetState), - ) { + ) => { if (isFunction(state)) { this.state = state(this.state) } else { diff --git a/widgets/antd/src/TableWidget/index.tsx b/widgets/antd/src/TableWidget/index.tsx index 56750c5..5ab602a 100644 --- a/widgets/antd/src/TableWidget/index.tsx +++ b/widgets/antd/src/TableWidget/index.tsx @@ -8,6 +8,7 @@ import { MRSchemeTableWidgetState } from './metadata' const DEFAULT_COLUMN_WIDTH = 150 +// TODO 实现 self 和 currentRow export const TableWidget: FC< InferWidgetState > = ({ instance, renderSlots, renderSlotPaths, columns, size, dataSource }) => { @@ -27,8 +28,22 @@ export const TableWidget: FC< // TODO ellipsis // ellipsis: true, } - if (c.mappedValue) { - res.renderText = () => c.mappedValue + if (!c.buildIn) { + res.render = (val, record, index) => { + return ( +
+ {renderSlots.custom_column_1} +
+ ) + } + } + if (c.mappedValue && c.buildIn) { + res.renderText = (text, record, index) => { + return c.mappedValue + } } if (c.width > 0) { res.width = c.width @@ -37,7 +52,7 @@ export const TableWidget: FC< } return res }) - }, [columns]) + }, [columns, instance.widgetId, renderSlotPaths.custom_column_1]) // FIXME 修改属性面板fixed需要刷新页面才会生效 return ( @@ -47,12 +62,11 @@ export const TableWidget: FC< size={size ?? undefined} data-widget-root data-widget-id={instance.widgetId} - data-widget-slot-path={renderSlotPaths.children} columns={_columns} dataSource={isArray(dataSource) ? dataSource : []} search={false} options={false} - rowKey={'id'} + rowKey={(record) => record.id || Math.random()} cardProps={{ bodyStyle: { padding: 0, diff --git a/widgets/antd/src/TableWidget/metadata.tsx b/widgets/antd/src/TableWidget/metadata.tsx index 8c3d4ad..100884b 100644 --- a/widgets/antd/src/TableWidget/metadata.tsx +++ b/widgets/antd/src/TableWidget/metadata.tsx @@ -63,6 +63,9 @@ export const MRSchemeTableWidgetProps = WidgetMetadata.createMRWidgetProps({ }, }, }, + slots: { + custom_column_1: mr.array(mr.string()).default([]), + }, }) export const MRSchemeTableWidgetState = WidgetMetadata.createMRWidgetState( @@ -78,7 +81,11 @@ export const tableWidgetMetadata = WidgetMetadata.createMetadata< type: 'TableWidget', name: '表格', icon: , - slots: {}, + slots: { + custom_column_1: { + name: '自定义列1', + }, + }, setters: { ColumnsSetter, }, diff --git a/widgets/antd/src/TableWidget/setters/ColumnsSetter/ColumnsSetter.tsx b/widgets/antd/src/TableWidget/setters/ColumnsSetter/ColumnsSetter.tsx index 706dbc4..1359d3a 100644 --- a/widgets/antd/src/TableWidget/setters/ColumnsSetter/ColumnsSetter.tsx +++ b/widgets/antd/src/TableWidget/setters/ColumnsSetter/ColumnsSetter.tsx @@ -28,7 +28,7 @@ import { import { createPortal } from 'react-dom' import { mcss, useTheme } from '@modou/css-in-js' -import { BaseSetterProps } from '@modou/setters' +import { BaseWidgetSetterProps } from '@modou/setters/src/types' import { MOCK_TABLE_DATA } from '../../mock' import { ColumnValueTypeEnum } from '../../types' @@ -61,9 +61,10 @@ async function quicktypeJSON( }) } -export const ColumnsSetter: FC> = ({ +export const ColumnsSetter: FC> = ({ value = [], onChange, + widget, }) => { const dataSource = useMemo( () => From 628dda77896747e1dcf04d5070ebebb3be29d6a6 Mon Sep 17 00:00:00 2001 From: liulei Date: Wed, 25 Jan 2023 08:42:03 +0800 Subject: [PATCH 30/68] =?UTF-8?q?refactor(widget):=20nativeSetter=20?= =?UTF-8?q?=E5=8F=82=E6=95=B0=20=E5=8F=98=E4=B8=BAobserver=20params?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 - .../components/CanvasDesignerPropsPanel.tsx | 12 +- packages/meta-vfs/src/WidgetFile/index.ts | 17 +- packages/meta-vfs/src/index.ts | 2 +- packages/setters/src/types/index.ts | 8 +- .../state-manager/src/WidgetState/index.ts | 2 +- pnpm-lock.yaml | 6 - .../setters/ColumnsSetter/ColumnsSetter.tsx | 198 +++++++++--------- 8 files changed, 120 insertions(+), 126 deletions(-) diff --git a/package.json b/package.json index 41673a5..35f74f1 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,6 @@ "flat": "^5.0.2", "handlebars": "^4.7.7", "immer": "^9.0.15", - "immutability-helper": "^3.1.1", "json-schema": "^0.4.0", "lodash": "^4.17.21", "mitt": "^3.0.0", diff --git a/packages/canvas-designer/src/components/CanvasDesignerPropsPanel.tsx b/packages/canvas-designer/src/components/CanvasDesignerPropsPanel.tsx index b702c6e..522215f 100644 --- a/packages/canvas-designer/src/components/CanvasDesignerPropsPanel.tsx +++ b/packages/canvas-designer/src/components/CanvasDesignerPropsPanel.tsx @@ -48,17 +48,7 @@ const useRenderFormItem = ({ widgetId }: { widgetId: string }) => { label={setterOptions.label} > {NativeSetter ? ( - { - widget.updateMeta( - produce((draft) => { - draft.props[key] = value - }), - ) - }} - /> + ) : ( +export type WidgetFileMeta = + BaseFileMete -export class WidgetFile extends BaseFile<{}, WidgetFileMeta, PageFile> { - protected constructor(meta: WidgetFileMeta, parentFile: PageFile) { +export class WidgetFile< + T extends WidgetBaseProps = WidgetBaseProps, +> extends BaseFile<{}, WidgetFileMeta, PageFile> { + protected constructor(meta: WidgetFileMeta, parentFile: PageFile) { super({ fileType: FileTypeEnum.Widget, meta, parentFile }) makeObservable(this, { subFileMap: observable, @@ -139,7 +142,7 @@ export class WidgetFile extends BaseFile<{}, WidgetFileMeta, PageFile> { static create(meta: Omit, parentFile: PageFile) { return runInAction(() => { - const widgetFile = new WidgetFile( + const widgetFile = new WidgetFile( { ...meta, version: '0.0.1', diff --git a/packages/meta-vfs/src/index.ts b/packages/meta-vfs/src/index.ts index c752504..49e7ccf 100644 --- a/packages/meta-vfs/src/index.ts +++ b/packages/meta-vfs/src/index.ts @@ -5,7 +5,7 @@ configure({ enforceActions: 'always', // computedRequiresReaction: true, // observableRequiresReaction: true, - reactionRequiresObservable: true, + reactionRequiresObservable: false, }) export * from './AppFile' diff --git a/packages/setters/src/types/index.ts b/packages/setters/src/types/index.ts index 67c29cf..d83780e 100644 --- a/packages/setters/src/types/index.ts +++ b/packages/setters/src/types/index.ts @@ -1,4 +1,5 @@ -import { WidgetFile } from '@modou/meta-vfs' +import { WidgetBaseProps } from '@modou/core' +import { WidgetFile, WidgetFileMeta } from '@modou/meta-vfs' import { MRType } from '@modou/refine' import { SETTER_KEY, SetterTypeEnum } from '../constants' @@ -19,10 +20,9 @@ export interface BaseSetterProps { options?: O } -export interface BaseWidgetSetterProps - extends BaseSetterProps { +export interface BaseWidgetSetterProps { // TODO widget meta - widget: WidgetFile + widget: WidgetFile> } export interface BaseMRSetterOptions { diff --git a/packages/state-manager/src/WidgetState/index.ts b/packages/state-manager/src/WidgetState/index.ts index c410574..26f3f36 100644 --- a/packages/state-manager/src/WidgetState/index.ts +++ b/packages/state-manager/src/WidgetState/index.ts @@ -22,7 +22,7 @@ export class WidgetState { console.log('rawMeta', rawMeta) // TODO 这个地方就要 eval this.state = { - ...toJS(rawMeta.props), + ...rawMeta.props, // TODO initState 传递的参数应该是初始化的state 或者 计算后的 props ...widgetDef.metadata.initState(rawMeta), } as unknown as BaseWidgetState diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e4cd381..97ebd04 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -52,7 +52,6 @@ importers: flat: ^5.0.2 handlebars: ^4.7.7 immer: ^9.0.15 - immutability-helper: ^3.1.1 json-schema: ^0.4.0 lodash: ^4.17.21 mitt: ^3.0.0 @@ -94,7 +93,6 @@ importers: flat: 5.0.2 handlebars: 4.7.7 immer: 9.0.15 - immutability-helper: 3.1.1 json-schema: 0.4.0 lodash: 4.17.21 mitt: 3.0.0 @@ -9682,10 +9680,6 @@ packages: resolution: {integrity: sha512-2eB/sswms9AEUSkOm4SbV5Y7Vmt/bKRwByd52jfLkW4OLYeaTP3EEiJ9agqU0O/tq6Dk62Zfj+TJSqfm1rLVGQ==} dev: false - /immutability-helper/3.1.1: - resolution: {integrity: sha512-Q0QaXjPjwIju/28TsugCHNEASwoCcJSyJV3uO1sOIQGI0jKgm9f41Lvz0DZj3n46cNCyAZTsEYoY4C2bVRUzyQ==} - dev: false - /immutable/4.1.0: resolution: {integrity: sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==} dev: true diff --git a/widgets/antd/src/TableWidget/setters/ColumnsSetter/ColumnsSetter.tsx b/widgets/antd/src/TableWidget/setters/ColumnsSetter/ColumnsSetter.tsx index 1359d3a..9a4aa04 100644 --- a/widgets/antd/src/TableWidget/setters/ColumnsSetter/ColumnsSetter.tsx +++ b/widgets/antd/src/TableWidget/setters/ColumnsSetter/ColumnsSetter.tsx @@ -8,8 +8,6 @@ import { import { useMemoizedFn, useMount, useUpdate } from 'ahooks' import { Button, Space, Table } from 'antd' import { ColumnsType } from 'antd/es/table' -import produce from 'immer' -import update from 'immutability-helper' import { JSONSchema7 } from 'json-schema' import { isBoolean } from 'lodash' import { @@ -17,19 +15,16 @@ import { jsonInputForTargetLanguage, quicktype, } from 'quicktype-core' -import { - FC, - HTMLAttributes, - useCallback, - useMemo, - useRef, - useState, -} from 'react' +import { FC, HTMLAttributes, useRef, useState } from 'react' import { createPortal } from 'react-dom' import { mcss, useTheme } from '@modou/css-in-js' +import { runInAction, toJS } from '@modou/reactivity' +import { Observer, observer, useComputed } from '@modou/reactivity-react' import { BaseWidgetSetterProps } from '@modou/setters/src/types' +import { InterWidgetProps } from '../../../_' +import { MRSchemeTableWidgetProps } from '../../metadata' import { MOCK_TABLE_DATA } from '../../mock' import { ColumnValueTypeEnum } from '../../types' import { ColumnSetting } from './ColumnSetting' @@ -61,40 +56,24 @@ async function quicktypeJSON( }) } -export const ColumnsSetter: FC> = ({ - value = [], - onChange, - widget, -}) => { - const dataSource = useMemo( - () => - value.map((v, index) => ({ - ...v, - key: v.dataIndex || index, - })), - [value], - ) - +const _ColumnsSetter: FC< + BaseWidgetSetterProps> +> = ({ widget }) => { const components = { body: { row: DraggableBodyRow, }, } - const moveRow = useCallback( - (dragIndex: number, hoverIndex: number) => { - const dragRow = value[dragIndex] - onChange( - update(value, { - $splice: [ - [dragIndex, 1], - [hoverIndex, 0, dragRow], - ], - }), - ) - }, - [onChange, value], - ) + const moveRow = useMemoizedFn((dragIndex: number, hoverIndex: number) => { + const dragRow = widget.meta.props.columns[dragIndex] + runInAction(() => { + widget.meta.props.columns[dragIndex] = + widget.meta.props.columns[hoverIndex] + widget.meta.props.columns[hoverIndex] = dragRow + }) + }) + const wrapperRef = useRef(null) const theme = useTheme() @@ -108,31 +87,38 @@ export const ColumnsSetter: FC> = ({ ?.previousElementSibling const [currentColumnIndex, setCurrentColumnIndex] = useState(0) - const addColumn = () => { - onChange([...value, generateDefaultColumn(value)]) - setCurrentColumnIndex(value.length) - } - const removeColumn = (index: number) => { - onChange( - produce(value, (draft) => { - draft.splice(index, 1) - }), - ) - } + const addColumn = useMemoizedFn(() => { + runInAction(() => { + widget.meta.props.columns.push( + generateDefaultColumn(toJS(widget.meta.props.columns)), + ) + }) + setCurrentColumnIndex(widget.meta.props.columns.length) + }) + const removeColumn = useMemoizedFn((index: number) => { + runInAction(() => { + widget.meta.props.columns.splice(index, 1) + }) + }) const editColumn = (index: number) => { setCurrentColumnIndex(index) } - const currentColumn = value[currentColumnIndex] + const currentColumn = widget.meta.props.columns[currentColumnIndex] const updateCurrentColumn = useMemoizedFn((newColumn: TableWidgetColumn) => { - onChange( - produce(value, (draft) => { - draft[currentColumnIndex] = newColumn - }), - ) + runInAction(() => { + widget.meta.props.columns[currentColumnIndex] = newColumn + }) }) + const columnsDataSource = useComputed(() => + widget.meta.props.columns.map((v, index) => ({ + ...v, + key: v.dataIndex || index, + })), + ) + const columns: ColumnsType = [ { title: '列标题', @@ -141,17 +127,21 @@ export const ColumnsSetter: FC> = ({ align: 'center', render: (value) => { return ( -
- - - {value} - -
+ + {() => ( +
+ + + {value} + +
+ )} +
) }, }, @@ -161,34 +151,48 @@ export const ColumnsSetter: FC> = ({ key: 'operation', align: 'center', render: (_value, record, index) => ( - <> - - - - {!record.buildIn && ( - - )} + + {() => ( + <> + + + + {!record.buildIn && ( + + )} - {record.buildIn && ( - + {record.buildIn && ( + + )} + )} - + ), }, ] @@ -206,7 +210,7 @@ export const ColumnsSetter: FC> = ({ const schemeRoot: JSONSchema7 = scheme.definitions! .RootElement as unknown as JSONSchema7 - const usedDataIndex = value.map((v) => v.dataIndex) + const usedDataIndex = widget.meta.props.columns.map((v) => v.dataIndex) Object.entries(schemeRoot.properties!).forEach(([prop, scheme]) => { // format [date-time, uri] if (isBoolean(scheme)) { @@ -255,7 +259,9 @@ export const ColumnsSetter: FC> = ({ } }) - onChange([...value, ...columns]) + runInAction(() => { + widget.meta.props.columns.push(...columns) + }) }) return ( @@ -281,7 +287,7 @@ export const ColumnsSetter: FC> = ({ pagination={false} size={'small'} columns={columns} - dataSource={dataSource} + dataSource={columnsDataSource} components={components} onRow={(_, index) => { const attr = { @@ -295,6 +301,8 @@ export const ColumnsSetter: FC> = ({ ) } +export const ColumnsSetter = observer(_ColumnsSetter) + const classes = { wrapper: mcss` .ant-table tr.drop-over-downward td { From 075c5f4c0aa78bde07080f61fdbd538cecc88621 Mon Sep 17 00:00:00 2001 From: liulei Date: Wed, 25 Jan 2023 13:22:35 +0800 Subject: [PATCH 31/68] =?UTF-8?q?feat(widget):=20tableWidget=20=E9=80=82?= =?UTF-8?q?=E9=85=8D=20dynamicSlots?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/CanvasDesignerOutlineTree.tsx | 1 - .../indicatoir/DropIndicator.tsx | 27 +++++++++----- .../src/hooks/usePageOutlineTree.tsx | 13 ++++--- .../src/hooks/useWidgetDrop.ts | 14 ++++---- packages/core/src/widget/WidgetMetadata.ts | 1 - packages/core/src/widget/hooks/index.ts | 1 + .../src/widget/hooks/useWidgetMetaSlots.ts | 16 +++++++++ packages/core/src/widget/index.ts | 1 + packages/meta-vfs/src/PageFile/index.ts | 29 ++++++++------- packages/meta-vfs/src/WidgetFile/index.ts | 8 +++++ packages/reactivity-react/src/index.ts | 2 +- packages/reactivity-react/src/useComputed.ts | 16 ++++----- .../render/src/components/WidgetVirtual.tsx | 27 +++++++++----- widgets/antd/src/InputWidget/index.tsx | 1 - widgets/antd/src/TableWidget/index.tsx | 18 +++++----- widgets/antd/src/TableWidget/metadata.tsx | 10 ++---- .../setters/ColumnsSetter/ColumnsSetter.tsx | 35 +++++++++++-------- 17 files changed, 134 insertions(+), 86 deletions(-) create mode 100644 packages/core/src/widget/hooks/index.ts create mode 100644 packages/core/src/widget/hooks/useWidgetMetaSlots.ts diff --git a/packages/canvas-designer/src/components/CanvasDesignerOutlineTree.tsx b/packages/canvas-designer/src/components/CanvasDesignerOutlineTree.tsx index 1332916..85b73c9 100644 --- a/packages/canvas-designer/src/components/CanvasDesignerOutlineTree.tsx +++ b/packages/canvas-designer/src/components/CanvasDesignerOutlineTree.tsx @@ -144,7 +144,6 @@ const _CanvasDesignerOutlineTree: FC = () => { // useEffect(() => { // console.log('tree.ref', ref.current?.state.flattenNodes) // }) - // FIXME 跨层架拖拽 return (
diff --git a/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/DropIndicator.tsx b/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/DropIndicator.tsx index 9acc22f..604f70a 100644 --- a/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/DropIndicator.tsx +++ b/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/DropIndicator.tsx @@ -14,9 +14,9 @@ import { useState, } from 'react' -import { AppFactoryContext } from '@modou/core' +import { AppFactoryContext, useWidgetMetaSlots } from '@modou/core' import { mcss, useTheme } from '@modou/css-in-js' -import { observer, useComputed } from '@modou/reactivity-react' +import { observer } from '@modou/reactivity-react' import { SimulatorInstanceContext } from '../../../contexts' import { useCanvasDesignerFile } from '../../../contexts/CanvasDesignerFileContext' @@ -88,7 +88,7 @@ const _WidgetDrop: ForwardRefRenderFunction = ( } }) - const dropIndicatorStyle: CSSProperties = useComputed(() => { + const dropIndicatorStyle: CSSProperties = (() => { if (!canvasDesignerStore.dropIndicator.show) { return {} } @@ -125,7 +125,7 @@ const _WidgetDrop: ForwardRefRenderFunction = ( default: return {} } - }) + })() const theme = useTheme() @@ -135,6 +135,11 @@ const _WidgetDrop: ForwardRefRenderFunction = ( forceUpdateStyle, })) + const allSlots = useWidgetMetaSlots({ + widgetMeta: widgetMetadata, + widget, + }) + return ( <> {isEmptySlot ? ( @@ -146,7 +151,7 @@ const _WidgetDrop: ForwardRefRenderFunction = ( > - {widgetMetadata.name}-{widgetMetadata.slots[slotPath].name} + {widgetMetadata.name}-{allSlots[slotPath].name} @@ -227,9 +232,15 @@ const _DropIndicator: FC = () => { }, ) const dropElementsRendered = useMemo(() => { - return dropElements.filter( - ({ widgetId }) => canvasDesignerFile.widgetMap[widgetId], - ) + // 去除列表模式下重复的widgetId + const usedWidgetIdMap: Record = {} + return dropElements.filter(({ widgetId, slotPath }) => { + const res = + !usedWidgetIdMap[widgetId + slotPath] && + canvasDesignerFile.widgetMap[widgetId] + usedWidgetIdMap[widgetId + slotPath] = true + return res + }) }, [canvasDesignerFile.widgetMap, dropElements]) return ( <> diff --git a/packages/canvas-designer/src/hooks/usePageOutlineTree.tsx b/packages/canvas-designer/src/hooks/usePageOutlineTree.tsx index d5cc1ee..43e4ae9 100644 --- a/packages/canvas-designer/src/hooks/usePageOutlineTree.tsx +++ b/packages/canvas-designer/src/hooks/usePageOutlineTree.tsx @@ -35,7 +35,6 @@ export const usePageOutlineTree = () => { const { appManager } = useAppManager() const rootWidget = appManager.widgetMap[canvasDesignerFile.meta.rootWidgetId] const appFactory = useContext(AppFactoryContext) - const parentTreeNodes: OutlineTreeNode[] = [ { key: canvasDesignerFile.meta.id, @@ -63,8 +62,12 @@ export const usePageOutlineTree = () => { const parentTreeNode = parentTreeNodes.pop() parentTreeNode?.children.unshift(curTreeNode) const widgetDef = appFactory.widgetByType[curNode.type] - if (!isEmpty(widgetDef.metadata.slots)) { - Object.entries(widgetDef.metadata.slots).forEach(([path, slot]) => { + const allSlots = { + ...widgetDef.metadata.slots, + ...(curNode.dynamicSlots as unknown as Record), + } + if (!isEmpty(allSlots)) { + Object.entries(allSlots).forEach(([path, slot]) => { nodeStack.push({ _type: 'slot', path, widgetId: curNode.id, ...slot }) parentTreeNodes.push(curTreeNode) }) @@ -83,12 +86,12 @@ export const usePageOutlineTree = () => { const parentTreeNode = parentTreeNodes.pop() parentTreeNode?.children.unshift(curTreeNode) const curSlot = - appManager.widgetMap[curNode.widgetId]?.meta.slots?.[curNode.path] + appManager.widgetMap[curNode.widgetId]?.slots?.[curNode.path] if (curSlot && !isEmpty(curSlot)) { curSlot.forEach((widgetId: string) => { nodeStack.push({ _type: 'widget', - ...appManager.widgetMap[widgetId]?.meta!, + ...appManager.widgetMap[widgetId]?.meta, }) parentTreeNodes.push(curTreeNode) }) diff --git a/packages/canvas-designer/src/hooks/useWidgetDrop.ts b/packages/canvas-designer/src/hooks/useWidgetDrop.ts index 12c51ee..2d6ebdb 100644 --- a/packages/canvas-designer/src/hooks/useWidgetDrop.ts +++ b/packages/canvas-designer/src/hooks/useWidgetDrop.ts @@ -127,7 +127,7 @@ export const useWidgetDrop = ({ const widgetFactory = useContext(AppFactoryContext) const widget = canvasDesignerFile.widgetMap[widgetId]! - const isEmptySlot = !!slotPath && isEmpty(widget.meta.slots[slotPath]) + const isEmptySlot = !!slotPath && isEmpty(widget.slots[slotPath]) const getDropIndicator = useMemoizedFn(() => { return canvasDesignerStore.dropIndicator @@ -175,7 +175,7 @@ export const useWidgetDrop = ({ sourceWidgetId: item.widget.id, targetWidgetId: parent.props.id, targetSlotPath: parentSlotPath, - targetPosition: parent.props.slots[parentSlotPath].findIndex( + targetPosition: parent.file.slots[parentSlotPath].findIndex( (widgetId) => widget.meta.id === widgetId, ), }) @@ -187,7 +187,7 @@ export const useWidgetDrop = ({ sourceWidgetId: item.widget.id, targetWidgetId: parent.props.id, targetSlotPath: parentSlotPath, - targetPosition: parent.props.slots[parentSlotPath].findIndex( + targetPosition: parent.file.slots[parentSlotPath].findIndex( (widgetId) => widget.meta.id === widgetId, ), }) @@ -198,7 +198,7 @@ export const useWidgetDrop = ({ sourceWidgetId: item.widget.id, targetWidgetId: widget.meta.id, targetSlotPath: slotPath, - targetPosition: widget.meta.slots[slotPath].length, + targetPosition: widget.slots[slotPath].length, }) break default: @@ -211,7 +211,7 @@ export const useWidgetDrop = ({ sourceWidgetMeta: item.widget, targetWidgetId: parent.props.id, targetSlotPath: parentSlotPath, - targetPosition: parent.props.slots[parentSlotPath].findIndex( + targetPosition: parent.file.slots[parentSlotPath].findIndex( (widgetId) => widget.meta.id === widgetId, ), }) @@ -224,7 +224,7 @@ export const useWidgetDrop = ({ targetWidgetId: parent.props.id, targetSlotPath: parentSlotPath, targetPosition: - parent.props.slots[parentSlotPath].findIndex( + parent.file.slots[parentSlotPath].findIndex( (widgetId) => widget.meta.id === widgetId, ) + 1, }) @@ -235,7 +235,7 @@ export const useWidgetDrop = ({ sourceWidgetMeta: item.widget, targetWidgetId: widget.meta.id, targetSlotPath: slotPath, - targetPosition: widget.meta.slots[slotPath].length, + targetPosition: widget.slots[slotPath].length, }) break default: diff --git a/packages/core/src/widget/WidgetMetadata.ts b/packages/core/src/widget/WidgetMetadata.ts index 457fab3..61837d0 100644 --- a/packages/core/src/widget/WidgetMetadata.ts +++ b/packages/core/src/widget/WidgetMetadata.ts @@ -11,7 +11,6 @@ import { schemeToJsonDefault, } from '@modou/refine' import { - BaseSetterProps, MRArraySetterType, MRBooleanSetterType, MRNumberSetterType, diff --git a/packages/core/src/widget/hooks/index.ts b/packages/core/src/widget/hooks/index.ts new file mode 100644 index 0000000..95b1f9f --- /dev/null +++ b/packages/core/src/widget/hooks/index.ts @@ -0,0 +1 @@ +export { useWidgetMetaSlots } from './useWidgetMetaSlots' diff --git a/packages/core/src/widget/hooks/useWidgetMetaSlots.ts b/packages/core/src/widget/hooks/useWidgetMetaSlots.ts new file mode 100644 index 0000000..720433c --- /dev/null +++ b/packages/core/src/widget/hooks/useWidgetMetaSlots.ts @@ -0,0 +1,16 @@ +import { WidgetFile } from '@modou/meta-vfs' + +import { WidgetMetadata } from '../WidgetMetadata' + +export const useWidgetMetaSlots = ({ + widgetMeta, + widget, +}: { + widgetMeta: WidgetMetadata + widget: WidgetFile +}) => { + return { + ...(widgetMeta.slots || {}), + ...widget.meta.dynamicSlots, + } +} diff --git a/packages/core/src/widget/index.ts b/packages/core/src/widget/index.ts index 0994fea..eea59e0 100644 --- a/packages/core/src/widget/index.ts +++ b/packages/core/src/widget/index.ts @@ -1,2 +1,3 @@ export * from './WidgetMetadata' export * from './types' +export * from './hooks' diff --git a/packages/meta-vfs/src/PageFile/index.ts b/packages/meta-vfs/src/PageFile/index.ts index 2c2070f..b33902b 100644 --- a/packages/meta-vfs/src/PageFile/index.ts +++ b/packages/meta-vfs/src/PageFile/index.ts @@ -21,6 +21,7 @@ export interface PageFileMeta extends BaseFileMete { export interface RelationWidget { props: WidgetBaseProps + file: WidgetFile slotPath: string parent?: RelationWidget } @@ -64,16 +65,18 @@ export class PageFile extends BaseFile { if (!Reflect.has(pre, widgetId)) { pre[widgetId] = { props: cur.meta, + file: cur, slotPath: '', } } const parent = pre[widgetId] - if (!isEmpty(cur.meta.slots)) { - Object.entries(cur.meta.slots).forEach(([slotPath, slotChildren]) => { + if (!isEmpty(cur.slots)) { + Object.entries(cur.slots).forEach(([slotPath, slotChildren]) => { slotChildren.forEach((widgetId) => { if (!Reflect.has(pre, widgetId)) { pre[widgetId] = { props: this.widgetMap[widgetId].meta, + file: this.widgetMap[widgetId], parent, slotPath, } @@ -104,7 +107,7 @@ export class PageFile extends BaseFile { return } const sourceWidget = WidgetFile.create(sourceWidgetMeta, this) - targetWidget.meta.slots[targetSlotPath].splice( + targetWidget.slots[targetSlotPath].splice( targetPosition, 0, sourceWidget.meta.id, @@ -127,16 +130,16 @@ export class PageFile extends BaseFile { let sourceIndex = -1 draft.forEach((widget) => { // 删除 - if (isObject(widget.meta.slots)) { - Object.keys(widget.meta.slots).forEach((slotPath) => { + if (isObject(widget.slots)) { + Object.keys(widget.slots).forEach((slotPath) => { if (sourceIndex !== -1) { return } - sourceIndex = widget.meta.slots[slotPath].findIndex( + sourceIndex = widget.slots[slotPath].findIndex( (slotWidgetId) => slotWidgetId === sourceWidgetId, ) if (sourceIndex !== -1) { - widget.meta.slots[slotPath].splice(sourceIndex, 1) + widget.slots[slotPath].splice(sourceIndex, 1) } }) } @@ -149,7 +152,7 @@ export class PageFile extends BaseFile { this.widgetRelationById[sourceWidgetId].slotPath === targetSlotPath if (isSameParentSlot) { - widget.meta.slots[targetSlotPath].splice( + widget.slots[targetSlotPath].splice( sourceIndex < targetPosition ? targetPosition - 1 : targetPosition, @@ -157,7 +160,7 @@ export class PageFile extends BaseFile { sourceWidgetId, ) } else { - widget.meta.slots[targetSlotPath].splice( + widget.slots[targetSlotPath].splice( targetPosition, 0, sourceWidgetId, @@ -173,13 +176,13 @@ export class PageFile extends BaseFile { this.updateWidgets( produce((draft) => { draft.forEach((widget) => { - if (isObject(widget.meta.slots)) { - Object.keys(widget.meta.slots).forEach((slotPath) => { - const deletedIndex = widget.meta.slots[slotPath].findIndex( + if (isObject(widget.slots)) { + Object.keys(widget.slots).forEach((slotPath) => { + const deletedIndex = widget.slots[slotPath].findIndex( (slotWidgetId) => slotWidgetId === widgetId, ) if (deletedIndex !== -1) { - widget.meta.slots[slotPath].splice(deletedIndex, 1) + widget.slots[slotPath].splice(deletedIndex, 1) } }) } diff --git a/packages/meta-vfs/src/WidgetFile/index.ts b/packages/meta-vfs/src/WidgetFile/index.ts index d161f8b..ba7ffa3 100644 --- a/packages/meta-vfs/src/WidgetFile/index.ts +++ b/packages/meta-vfs/src/WidgetFile/index.ts @@ -57,6 +57,7 @@ export class WidgetFile< subFileMap: observable, // depMap: computed.struct, flattenedMetaValMap: computed.struct, + slots: computed.struct, }) } @@ -115,6 +116,13 @@ export class WidgetFile< ) } + get slots() { + return { + ...this.meta.slots, + ...mapValues(this.meta.dynamicSlots || {}, (v) => v.children), + } + } + // TODO state 修改为主动 watch dep // 按钮-{{colDSL.span}} // get depMap(): Record { diff --git a/packages/reactivity-react/src/index.ts b/packages/reactivity-react/src/index.ts index d45aef4..03adf69 100644 --- a/packages/reactivity-react/src/index.ts +++ b/packages/reactivity-react/src/index.ts @@ -41,4 +41,4 @@ export function useStaticRendering(enable: boolean) { enableStaticRendering(enable) } -export { useComputed } from './useComputed' +// export { useComputed } from './useComputed' diff --git a/packages/reactivity-react/src/useComputed.ts b/packages/reactivity-react/src/useComputed.ts index 124d5d7..f8b8a07 100644 --- a/packages/reactivity-react/src/useComputed.ts +++ b/packages/reactivity-react/src/useComputed.ts @@ -1,9 +1,9 @@ -import { useLocalObservable } from './useLocalObservable' +// import { useLocalObservable } from './useLocalObservable' -export const useComputed = (factory: () => T): T => { - return useLocalObservable(() => ({ - get value() { - return factory() - }, - })).value -} +// export const useComputed = (factory: () => T): T => { +// return useLocalObservable(() => ({ +// get value() { +// return factory() +// }, +// })).value +// } diff --git a/packages/render/src/components/WidgetVirtual.tsx b/packages/render/src/components/WidgetVirtual.tsx index 254f5cf..732a465 100644 --- a/packages/render/src/components/WidgetVirtual.tsx +++ b/packages/render/src/components/WidgetVirtual.tsx @@ -1,8 +1,13 @@ import { get, head, isNumber, omit, set, take, takeRight, unset } from 'lodash' -import { FC, useContext, useEffect } from 'react' +import { all } from 'quicktype-core/dist/language/All' +import { FC, useContext, useEffect, useMemo } from 'react' import * as React from 'react' -import { AppFactoryContext, useAppManager } from '@modou/core' +import { + AppFactoryContext, + useAppManager, + useWidgetMetaSlots, +} from '@modou/core' import { IReactionDisposer, autorun, @@ -11,7 +16,7 @@ import { runInAction, toJS, } from '@modou/reactivity' -import { observer, useComputed } from '@modou/reactivity-react' +import { observer } from '@modou/reactivity-react' import { WidgetState } from '@modou/state-manager' import { useStateManager } from '@modou/state-manager/src/contexts' @@ -35,12 +40,16 @@ const _WidgetVirtual: FC<{ // TODO any 替换 state 定义 const WidgetComponent = widgetDef.component - const renderSlots = useComputed(() => { - return Object.entries(widgetDef.metadata.slots || {}) + const allSlots = useWidgetMetaSlots({ + widgetMeta: widgetDef.metadata, + widget, + }) + const renderSlots = (() => { + return Object.entries(allSlots) .map(([slotPath, slot]) => { return { key: slotPath, - elements: widget.meta.slots[slotPath]?.map((widgetId) => ( + elements: widget.slots[slotPath]?.map((widgetId) => ( )), } @@ -51,8 +60,8 @@ const _WidgetVirtual: FC<{ Reflect.set(pre, key, elements) return pre }, {}) - }) - const renderSlotPaths = useComputed(() => { + })() + const renderSlotPaths = (() => { return Object.keys(renderSlots).reduce>( (pre, cur) => { pre[cur] = cur @@ -60,7 +69,7 @@ const _WidgetVirtual: FC<{ }, {}, ) - }) + })() useEffect(() => { const stopExps: IReactionDisposer[] = [] diff --git a/widgets/antd/src/InputWidget/index.tsx b/widgets/antd/src/InputWidget/index.tsx index 59e7efa..1522c2f 100644 --- a/widgets/antd/src/InputWidget/index.tsx +++ b/widgets/antd/src/InputWidget/index.tsx @@ -22,7 +22,6 @@ export const InputWidget: FC< fieldProps={{ defaultValue, onChange: (e) => { - console.log('onChange', e) updateState((prev) => ({ ...prev, value: e.target.value, diff --git a/widgets/antd/src/TableWidget/index.tsx b/widgets/antd/src/TableWidget/index.tsx index 5ab602a..768009f 100644 --- a/widgets/antd/src/TableWidget/index.tsx +++ b/widgets/antd/src/TableWidget/index.tsx @@ -29,15 +29,15 @@ export const TableWidget: FC< // ellipsis: true, } if (!c.buildIn) { + // @ts-expect-error + res.onCell = () => { + return { + 'data-widget-id': instance.widgetId, + 'data-widget-slot-path': c.dataIndex, + } + } res.render = (val, record, index) => { - return ( -
- {renderSlots.custom_column_1} -
- ) + return Reflect.get(renderSlots, c.dataIndex) } } if (c.mappedValue && c.buildIn) { @@ -52,7 +52,7 @@ export const TableWidget: FC< } return res }) - }, [columns, instance.widgetId, renderSlotPaths.custom_column_1]) + }, [columns]) // FIXME 修改属性面板fixed需要刷新页面才会生效 return ( diff --git a/widgets/antd/src/TableWidget/metadata.tsx b/widgets/antd/src/TableWidget/metadata.tsx index 100884b..91c5e70 100644 --- a/widgets/antd/src/TableWidget/metadata.tsx +++ b/widgets/antd/src/TableWidget/metadata.tsx @@ -63,9 +63,7 @@ export const MRSchemeTableWidgetProps = WidgetMetadata.createMRWidgetProps({ }, }, }, - slots: { - custom_column_1: mr.array(mr.string()).default([]), - }, + slots: {}, }) export const MRSchemeTableWidgetState = WidgetMetadata.createMRWidgetState( @@ -81,11 +79,7 @@ export const tableWidgetMetadata = WidgetMetadata.createMetadata< type: 'TableWidget', name: '表格', icon: , - slots: { - custom_column_1: { - name: '自定义列1', - }, - }, + slots: {}, setters: { ColumnsSetter, }, diff --git a/widgets/antd/src/TableWidget/setters/ColumnsSetter/ColumnsSetter.tsx b/widgets/antd/src/TableWidget/setters/ColumnsSetter/ColumnsSetter.tsx index 9a4aa04..2756819 100644 --- a/widgets/antd/src/TableWidget/setters/ColumnsSetter/ColumnsSetter.tsx +++ b/widgets/antd/src/TableWidget/setters/ColumnsSetter/ColumnsSetter.tsx @@ -19,8 +19,8 @@ import { FC, HTMLAttributes, useRef, useState } from 'react' import { createPortal } from 'react-dom' import { mcss, useTheme } from '@modou/css-in-js' -import { runInAction, toJS } from '@modou/reactivity' -import { Observer, observer, useComputed } from '@modou/reactivity-react' +import { remove, runInAction, set, toJS } from '@modou/reactivity' +import { Observer, observer } from '@modou/reactivity-react' import { BaseWidgetSetterProps } from '@modou/setters/src/types' import { InterWidgetProps } from '../../../_' @@ -56,7 +56,7 @@ async function quicktypeJSON( }) } -const _ColumnsSetter: FC< +const UOColumnsSetter: FC< BaseWidgetSetterProps> > = ({ widget }) => { const components = { @@ -89,14 +89,23 @@ const _ColumnsSetter: FC< const addColumn = useMemoizedFn(() => { runInAction(() => { - widget.meta.props.columns.push( - generateDefaultColumn(toJS(widget.meta.props.columns)), - ) + const newColumn = generateDefaultColumn(toJS(widget.meta.props.columns)) + const newDynamicSlot: typeof widget.meta.dynamicSlots['1'] = { + name: newColumn.title || newColumn.dataIndex, + children: [], + } + widget.meta.props.columns.push(newColumn) + set(widget.meta, 'dynamicSlots', { + ...widget.meta.dynamicSlots, + [newColumn.dataIndex]: newDynamicSlot, + }) }) setCurrentColumnIndex(widget.meta.props.columns.length) }) const removeColumn = useMemoizedFn((index: number) => { runInAction(() => { + const toRemovedColumn = widget.meta.props.columns[index] + remove(widget.meta.dynamicSlots, toRemovedColumn.dataIndex) widget.meta.props.columns.splice(index, 1) }) }) @@ -112,12 +121,10 @@ const _ColumnsSetter: FC< }) }) - const columnsDataSource = useComputed(() => - widget.meta.props.columns.map((v, index) => ({ - ...v, - key: v.dataIndex || index, - })), - ) + const columnsDataSource = widget.meta.props.columns.map((v, index) => ({ + ...v, + key: v.dataIndex || index, + })) const columns: ColumnsType = [ { @@ -273,7 +280,6 @@ const _ColumnsSetter: FC< }} > - {operationWrapper && createPortal( @@ -301,8 +307,7 @@ const _ColumnsSetter: FC< ) } -export const ColumnsSetter = observer(_ColumnsSetter) - +export const ColumnsSetter = observer(UOColumnsSetter) const classes = { wrapper: mcss` .ant-table tr.drop-over-downward td { From b5c7b0d76ea9780caa96a17de0a59210c4b1b59e Mon Sep 17 00:00:00 2001 From: liulei Date: Wed, 25 Jan 2023 13:46:50 +0800 Subject: [PATCH 32/68] =?UTF-8?q?fix(widget):=20=E4=B8=AA=E5=88=AB?= =?UTF-8?q?=E7=BB=84=E4=BB=B6hovering=E4=B8=8D=E6=98=BE=E7=A4=BA=E6=8C=87?= =?UTF-8?q?=E7=A4=BA=E5=99=A8=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- widgets/antd/src/ButtonWidget/index.tsx | 1 + widgets/antd/src/InputWidget/index.tsx | 1 + 2 files changed, 2 insertions(+) diff --git a/widgets/antd/src/ButtonWidget/index.tsx b/widgets/antd/src/ButtonWidget/index.tsx index f75a12b..41bcbc8 100644 --- a/widgets/antd/src/ButtonWidget/index.tsx +++ b/widgets/antd/src/ButtonWidget/index.tsx @@ -24,6 +24,7 @@ export const ButtonWidget: FC< }) return ( + +
+ ) +} + +export const FlowCanvas: FC> = (props) => { + return ( + + <_FlowCanvas {...props} /> + + ) +} + +const classes = { + wrapper: mcss` + height: 600px; + `, +} diff --git a/packages/flow-nodes/src/_/styles/index.ts b/packages/flow-nodes/src/_/styles/index.ts new file mode 100644 index 0000000..769b476 --- /dev/null +++ b/packages/flow-nodes/src/_/styles/index.ts @@ -0,0 +1,43 @@ +import { mcss } from '@modou/css-in-js' + +export const nodeClasses = { + // node: mcss` + // border-radius: 8px; + // display: flex; + // height: 60px; + // width: 300px; + // letter-spacing: -0.2px; + // box-shadow: var(--node-box-shadow); + // `, + wrapper: mcss` + border: 1px solid red; + border-radius: 8px; + //height: 40px; + width: 300px; + `, + wrapperHeader: mcss` + background-color: #888888; + height: 36px; + display: flex; + align-items: center; + padding: 0 16px; + `, + wrapperBody: mcss` + background-color: #747bff; + padding: 16px; + `, + nodeTargetPort: mcss` + background-color: #535bf2; + `, + nodeSourcePort: mcss` + background-color: seagreen; + height: 10px; + width: 10px; + &.react-flow__handle-right{ + right: -12px; + } + &.react-flow__handle-bottom{ + bottom: -12px; + } + `, +} diff --git a/packages/flow-nodes/src/_/types/index.ts b/packages/flow-nodes/src/_/types/index.ts new file mode 100644 index 0000000..feae634 --- /dev/null +++ b/packages/flow-nodes/src/_/types/index.ts @@ -0,0 +1,17 @@ +export enum FlowNodeEnum { + // 开始 + START_NODE = 'START_NODE', + // 循环 + LOOP_NODE = 'LOOP_NODE', + // 条件分支 + BRANCH_NODE = 'BRANCH_NODE', + // 执行脚本 + RUN_SCRIPT_NODE = 'RUN_SCRIPT_NODE', + // 调用子流程 + INVOKE_SUB_FLOW = 'INVOKE_SUB_FLOW', +} + +export enum FlowNodeStatus { + Expand, + Collapse, +} diff --git a/packages/flow-nodes/src/index.ts b/packages/flow-nodes/src/index.ts new file mode 100644 index 0000000..fa276ad --- /dev/null +++ b/packages/flow-nodes/src/index.ts @@ -0,0 +1,2 @@ +export * from './StartNode' +export * from './StartNode/metadata' diff --git a/packages/flow-nodes/tsconfig.json b/packages/flow-nodes/tsconfig.json new file mode 100644 index 0000000..a4e40b0 --- /dev/null +++ b/packages/flow-nodes/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "strict": true, + "declaration": true, + "skipLibCheck": true, + "esModuleInterop": true, + "jsx": "react-jsx", + "baseUrl": "./", + "paths": { + "@@/*": [".dumi/tmp/*"], + "@modou/flow-nodes": ["src"], + "@modou/flow-nodes/*": ["src/*", "*"] + } + }, + "include": [".dumi/**/*", ".dumirc.ts", "src/**/*"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2fe0010..6102306 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -66,7 +66,7 @@ importers: react-dom: ^18.2.0 react-json-view: ^1.21.3 react-router-dom: ^6.3.0 - reactflow: ^11.3.0 + reactflow: ^11.5.1 rollup-plugin-visualizer: ^5.8.2 ts-pattern: ^4.0.5 typescript: ^4.7.4 @@ -107,7 +107,7 @@ importers: react-dom: 18.2.0_react@18.2.0 react-json-view: 1.21.3_rj7ozvcq3uehdlnj3cbwzbi5ce react-router-dom: 6.4.2_biqbaboplfbrettd7655fr4n2y - reactflow: 11.3.0_biqbaboplfbrettd7655fr4n2y + reactflow: 11.5.1_biqbaboplfbrettd7655fr4n2y ts-pattern: 4.0.5 devDependencies: '@emotion/babel-plugin': 11.10.5 @@ -235,6 +235,70 @@ importers: packages/evaluate: specifiers: {} + packages/flow-designer: + specifiers: + '@commitlint/cli': ^17.1.2 + '@commitlint/config-conventional': ^17.1.0 + '@umijs/lint': ^4.0.0 + dumi: ^2.0.2 + eslint: ^8.23.0 + father: ^4.1.0 + husky: ^8.0.1 + lint-staged: ^13.0.3 + prettier: ^2.7.1 + prettier-plugin-organize-imports: ^3.0.0 + prettier-plugin-packagejson: ^2.2.18 + react: ^18.0.0 + react-dom: ^18.0.0 + stylelint: ^14.9.1 + devDependencies: + '@commitlint/cli': 17.3.0 + '@commitlint/config-conventional': 17.3.0 + '@umijs/lint': 4.0.40_tj73zugfbqmkftfxkbg3ziygai + dumi: 2.0.18_j6ognzfrot7iwqpseop24xzp7y + eslint: 8.25.0 + father: 4.1.1 + husky: 8.0.2 + lint-staged: 13.1.0 + prettier: 2.8.1 + prettier-plugin-organize-imports: 3.2.1_prettier@2.8.1 + prettier-plugin-packagejson: 2.3.0_prettier@2.8.1 + react: 18.2.0 + react-dom: 18.2.0_react@18.2.0 + stylelint: 14.16.1 + + packages/flow-nodes: + specifiers: + '@commitlint/cli': ^17.1.2 + '@commitlint/config-conventional': ^17.1.0 + '@umijs/lint': ^4.0.0 + dumi: ^2.0.2 + eslint: ^8.23.0 + father: ^4.1.0 + husky: ^8.0.1 + lint-staged: ^13.0.3 + prettier: ^2.7.1 + prettier-plugin-organize-imports: ^3.0.0 + prettier-plugin-packagejson: ^2.2.18 + react: ^18.0.0 + react-dom: ^18.0.0 + stylelint: ^14.9.1 + devDependencies: + '@commitlint/cli': 17.3.0 + '@commitlint/config-conventional': 17.3.0 + '@umijs/lint': 4.0.40_tj73zugfbqmkftfxkbg3ziygai + dumi: 2.0.18_j6ognzfrot7iwqpseop24xzp7y + eslint: 8.25.0 + father: 4.1.1 + husky: 8.0.2 + lint-staged: 13.1.0 + prettier: 2.8.1 + prettier-plugin-organize-imports: 3.2.1_prettier@2.8.1 + prettier-plugin-packagejson: 2.3.0_prettier@2.8.1 + react: 18.2.0 + react-dom: 18.2.0_react@18.2.0 + stylelint: 14.16.1 + packages/meta-vfs: specifiers: '@commitlint/cli': ^17.1.2 @@ -367,12 +431,10 @@ importers: '@ahooksjs/use-url-state': ^3.5.0 '@modou/canvas-designer': workspace:^1.0.0 mitt: ^3.0.0 - reactflow: ^11.2.0 dependencies: '@ahooksjs/use-url-state': 3.5.0 '@modou/canvas-designer': link:../../packages/canvas-designer mitt: 3.0.0 - reactflow: 11.2.0 widgets/antd: specifiers: @@ -2816,57 +2878,28 @@ packages: resolution: {integrity: sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA==} dev: false - /@reactflow/background/11.0.4: - resolution: {integrity: sha512-AACdU1B63BJCL0mO6I2ceehkv0ijKxzhh4UMc0JQs8sSgbAQjvnMSt/VcjIJ1e8V4o/wjPejj3xWm2Jxsv0Qhw==} + /@reactflow/background/11.1.3_biqbaboplfbrettd7655fr4n2y: + resolution: {integrity: sha512-U5h43dobrdYy+PdczS3wZRjDphjYemH4VPKZoi5HCeWsevqHqFSmQE+GC8RNXmWxYObqUA9EGSWlfCtWSg0HKQ==} peerDependencies: react: '>=17' react-dom: '>=17' dependencies: - '@babel/runtime': 7.20.7 - '@reactflow/core': 11.2.0 - classcat: 5.0.4 - zustand: 4.1.1 - transitivePeerDependencies: - - immer - dev: false - - /@reactflow/background/11.0.5_biqbaboplfbrettd7655fr4n2y: - resolution: {integrity: sha512-rQKqD3gCjhsy6tuKkRrSuCgZj66tdfdX6t58d73+84+lud1O3f+vj/JfFZC9ee5ZY4R/5kVzOpKOAPaGQZmhig==} - peerDependencies: - react: '>=17' - react-dom: '>=17' - dependencies: - '@babel/runtime': 7.20.7 - '@reactflow/core': 11.3.0_biqbaboplfbrettd7655fr4n2y + '@reactflow/core': 11.5.0_biqbaboplfbrettd7655fr4n2y classcat: 5.0.4 react: 18.2.0 react-dom: 18.2.0_react@18.2.0 - zustand: 4.1.1_react@18.2.0 - transitivePeerDependencies: - - immer - dev: false - - /@reactflow/controls/11.0.4: - resolution: {integrity: sha512-NLycgcW+hS2CcZiUqvTOXkug+UMmq7dzORxdzxosvBI0b1La+xNXi+UxVMlMAYrNZH3lm+SWyftksXQ/r010bQ==} - peerDependencies: - react: '>=17' - react-dom: '>=17' - dependencies: - '@babel/runtime': 7.20.7 - '@reactflow/core': 11.2.0 - classcat: 5.0.4 + zustand: 4.3.2_react@18.2.0 transitivePeerDependencies: - immer dev: false - /@reactflow/controls/11.0.5_biqbaboplfbrettd7655fr4n2y: - resolution: {integrity: sha512-a8rWtFnEZk7HyWbaWWjsaFssr5q++p9iCKVzuvYUuXFveJwTofRdkjq2nKlrszrMJLNeNZwDi9mYIwVqqds9aQ==} + /@reactflow/controls/11.1.3_biqbaboplfbrettd7655fr4n2y: + resolution: {integrity: sha512-lqh8Nymr+YzqhzjdXg5MhqhP2cZF5w+MErtB9aBUjAn/8zJbEz1bqzFxfmo/xFugtrK2ujW4HBix15zjv/6gzQ==} peerDependencies: react: '>=17' react-dom: '>=17' dependencies: - '@babel/runtime': 7.20.7 - '@reactflow/core': 11.3.0_biqbaboplfbrettd7655fr4n2y + '@reactflow/core': 11.5.0_biqbaboplfbrettd7655fr4n2y classcat: 5.0.4 react: 18.2.0 react-dom: 18.2.0_react@18.2.0 @@ -2874,27 +2907,8 @@ packages: - immer dev: false - /@reactflow/core/11.2.0: - resolution: {integrity: sha512-8rYp9bQON7MMtHZ3opU37Bfp4NaGGrJFeu+tcokz9bQZcGo43oCKl8xkURn8HlC8FnpVwpQ7e3DBdsOtnEbaEg==} - peerDependencies: - react: '>=17' - react-dom: '>=17' - dependencies: - '@types/d3': 7.4.0 - '@types/d3-drag': 3.0.1 - '@types/d3-selection': 3.0.3 - '@types/d3-zoom': 3.0.1 - classcat: 5.0.4 - d3-drag: 3.0.0 - d3-selection: 3.0.0 - d3-zoom: 3.0.0 - zustand: 4.1.1 - transitivePeerDependencies: - - immer - dev: false - - /@reactflow/core/11.3.0_biqbaboplfbrettd7655fr4n2y: - resolution: {integrity: sha512-RmxP/Vy7aImu4WfFYcvG25zWJirriMupaz25qX+75jbtakTKZHCTurA7jI6NgubUY1OlwcXqG9surCQgSu6+hQ==} + /@reactflow/core/11.5.0_biqbaboplfbrettd7655fr4n2y: + resolution: {integrity: sha512-3IhqgeuomNYyurgBRB+08+xdS2pjQfYDWVAuJhNW6U4sR0BHRPzPuAhztNXPNpTFk2K75revFB3/uPJ/aZblcw==} peerDependencies: react: '>=17' react-dom: '>=17' @@ -2909,37 +2923,18 @@ packages: d3-zoom: 3.0.0 react: 18.2.0 react-dom: 18.2.0_react@18.2.0 - zustand: 4.1.1_react@18.2.0 - transitivePeerDependencies: - - immer - dev: false - - /@reactflow/minimap/11.1.0: - resolution: {integrity: sha512-igquYRc9QdV5hu7KZiBjQgynvy/oMH5+i5eDvI0aLSkLC68NVnHFFpEZlk4bSVav+nGeWbHOZK/tryd3Sa39TQ==} - peerDependencies: - react: '>=17' - react-dom: '>=17' - dependencies: - '@babel/runtime': 7.20.7 - '@reactflow/core': 11.2.0 - '@types/d3-selection': 3.0.3 - '@types/d3-zoom': 3.0.1 - classcat: 5.0.4 - d3-selection: 3.0.0 - d3-zoom: 3.0.0 - zustand: 4.1.1 + zustand: 4.3.2_react@18.2.0 transitivePeerDependencies: - immer dev: false - /@reactflow/minimap/11.2.0_biqbaboplfbrettd7655fr4n2y: - resolution: {integrity: sha512-CORkxIVI+LNOk1fHRPSwiBFBXglt6gfHU+V5hBzF8ZsOhs0gxgHDTw+2ktvMsRkSKnnT58uPXEvdseksVonI2g==} + /@reactflow/minimap/11.3.3_biqbaboplfbrettd7655fr4n2y: + resolution: {integrity: sha512-EHyiWglFO/CMSERmkVRKtC2kKHWBYrOg2naXP5WD2rh24gm73B8Al1PJ7INuiaQHAEbS1iOw/uKi0up4spu8Ww==} peerDependencies: react: '>=17' react-dom: '>=17' dependencies: - '@babel/runtime': 7.20.7 - '@reactflow/core': 11.3.0_biqbaboplfbrettd7655fr4n2y + '@reactflow/core': 11.5.0_biqbaboplfbrettd7655fr4n2y '@types/d3-selection': 3.0.3 '@types/d3-zoom': 3.0.1 classcat: 5.0.4 @@ -2947,23 +2942,22 @@ packages: d3-zoom: 3.0.0 react: 18.2.0 react-dom: 18.2.0_react@18.2.0 - zustand: 4.1.1_react@18.2.0 + zustand: 4.3.2_react@18.2.0 transitivePeerDependencies: - immer dev: false - /@reactflow/node-toolbar/1.0.0_biqbaboplfbrettd7655fr4n2y: - resolution: {integrity: sha512-UP/X7Y9rfPVDEipOPP/MXWOK02+Yzuo3PIEPFDebDtUPDLu5EKeTENKAgpihy/YG5X2Bi2eh5XRs0bc3CsmRiw==} + /@reactflow/node-toolbar/1.1.3_biqbaboplfbrettd7655fr4n2y: + resolution: {integrity: sha512-D45OGjyo9F8kjKe66RS/qIsipEezlVn1dWGLsYZBkL3K/1zw/aSK/StJHdHLhonWRnDwPZyrcfCu9wbpZxDZlQ==} peerDependencies: react: '>=17' react-dom: '>=17' dependencies: - '@babel/runtime': 7.20.7 - '@reactflow/core': 11.3.0_biqbaboplfbrettd7655fr4n2y + '@reactflow/core': 11.5.0_biqbaboplfbrettd7655fr4n2y classcat: 5.0.4 react: 18.2.0 react-dom: 18.2.0_react@18.2.0 - zustand: 4.1.1_react@18.2.0 + zustand: 4.3.2_react@18.2.0 transitivePeerDependencies: - immer dev: false @@ -14076,31 +14070,17 @@ packages: react: 18.2.0 dev: false - /reactflow/11.2.0: - resolution: {integrity: sha512-wrpcpY1J1QY87meJXrd7Y1jZQ9s0VvXudpeMrXeq1HEgYOyYmZrg2oxv4ck9m9liq0Urz9z/eWrIQTkdb/6P5A==} - peerDependencies: - react: '>=17' - react-dom: '>=17' - dependencies: - '@reactflow/background': 11.0.4 - '@reactflow/controls': 11.0.4 - '@reactflow/core': 11.2.0 - '@reactflow/minimap': 11.1.0 - transitivePeerDependencies: - - immer - dev: false - - /reactflow/11.3.0_biqbaboplfbrettd7655fr4n2y: - resolution: {integrity: sha512-KU3Uwww0hjvF0Er5sA0Qy+e3KPJOn5bLpyxVooyef0MLDk/W5ybCmMvKKnML705GtJWChzHPNzHST5hCf5OflA==} + /reactflow/11.5.1_biqbaboplfbrettd7655fr4n2y: + resolution: {integrity: sha512-njujIQ5zoCREB5WCKWDZLQJOU6e4eY6M3eOvyMboqFUIbiUQwqzQ5FtM8njTCUZA1cYBGQLE2zGwdxa3RhYVbw==} peerDependencies: react: '>=17' react-dom: '>=17' dependencies: - '@reactflow/background': 11.0.5_biqbaboplfbrettd7655fr4n2y - '@reactflow/controls': 11.0.5_biqbaboplfbrettd7655fr4n2y - '@reactflow/core': 11.3.0_biqbaboplfbrettd7655fr4n2y - '@reactflow/minimap': 11.2.0_biqbaboplfbrettd7655fr4n2y - '@reactflow/node-toolbar': 1.0.0_biqbaboplfbrettd7655fr4n2y + '@reactflow/background': 11.1.3_biqbaboplfbrettd7655fr4n2y + '@reactflow/controls': 11.1.3_biqbaboplfbrettd7655fr4n2y + '@reactflow/core': 11.5.0_biqbaboplfbrettd7655fr4n2y + '@reactflow/minimap': 11.3.3_biqbaboplfbrettd7655fr4n2y + '@reactflow/node-toolbar': 1.1.3_biqbaboplfbrettd7655fr4n2y react: 18.2.0 react-dom: 18.2.0_react@18.2.0 transitivePeerDependencies: @@ -16052,12 +16032,6 @@ packages: react: 18.2.0 dev: false - /use-sync-external-store/1.2.0: - resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - dev: false - /use-sync-external-store/1.2.0_react@18.2.0: resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==} peerDependencies: @@ -16488,23 +16462,8 @@ packages: commander: 2.20.3 dev: true - /zustand/4.1.1: - resolution: {integrity: sha512-h4F3WMqsZgvvaE0n3lThx4MM81Ls9xebjvrABNzf5+jb3/03YjNTSgZXeyrvXDArMeV9untvWXRw1tY+ntPYbA==} - engines: {node: '>=12.7.0'} - peerDependencies: - immer: '>=9.0' - react: '>=16.8' - peerDependenciesMeta: - immer: - optional: true - react: - optional: true - dependencies: - use-sync-external-store: 1.2.0 - dev: false - - /zustand/4.1.1_react@18.2.0: - resolution: {integrity: sha512-h4F3WMqsZgvvaE0n3lThx4MM81Ls9xebjvrABNzf5+jb3/03YjNTSgZXeyrvXDArMeV9untvWXRw1tY+ntPYbA==} + /zustand/4.3.2_react@18.2.0: + resolution: {integrity: sha512-rd4haDmlwMTVWVqwvgy00ny8rtti/klRoZjFbL/MAcDnmD5qSw/RZc+Vddstdv90M5Lv6RPgWvm1Hivyn0QgJw==} engines: {node: '>=12.7.0'} peerDependencies: immer: '>=9.0' diff --git a/websites/workspace/package.json b/websites/workspace/package.json index bff2861..ffb2607 100644 --- a/websites/workspace/package.json +++ b/websites/workspace/package.json @@ -12,7 +12,6 @@ "dependencies": { "@ahooksjs/use-url-state": "^3.5.0", "@modou/canvas-designer": "workspace:^1.0.0", - "mitt": "^3.0.0", - "reactflow": "^11.2.0" + "mitt": "^3.0.0" } } From d8f573c792160bddaa4c90f997b7fe606d31ba36 Mon Sep 17 00:00:00 2001 From: liulei Date: Mon, 30 Jan 2023 06:11:48 +0800 Subject: [PATCH 54/68] =?UTF-8?q?feat(flow-nodes):=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=B5=81=E8=8A=82=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/code-editor/src/CodeEditor/index.tsx | 4 +- packages/code-editor/src/index.ts | 2 + packages/core/package.json | 2 +- .../core/src/flow-node/FlowNodeMetadata.ts | 67 +++++++--- packages/core/src/flow-node/index.ts | 1 + packages/core/src/flow-node/types.ts | 11 ++ .../flow-nodes/src/BranchNode/CaseBlock.tsx | 122 ++++++++++++++++++ .../flow-nodes/src/BranchNode/constants.ts | 1 + packages/flow-nodes/src/BranchNode/demo.tsx | 10 ++ packages/flow-nodes/src/BranchNode/index.md | 5 + packages/flow-nodes/src/BranchNode/index.tsx | 121 +++++++++++++++++ .../flow-nodes/src/BranchNode/metadata.tsx | 37 ++++++ packages/flow-nodes/src/LooptNode/demo.tsx | 10 ++ packages/flow-nodes/src/LooptNode/index.md | 5 + packages/flow-nodes/src/LooptNode/index.tsx | 43 ++++++ .../flow-nodes/src/LooptNode/metadata.tsx | 33 +++++ .../flow-nodes/src/RunScriptNode/demo.tsx | 12 ++ .../flow-nodes/src/RunScriptNode/index.md | 5 + .../flow-nodes/src/RunScriptNode/index.tsx | 49 +++++++ .../flow-nodes/src/RunScriptNode/metadata.tsx | 26 ++++ packages/flow-nodes/src/StartNode/demo.tsx | 4 +- packages/flow-nodes/src/StartNode/index.md | 3 +- packages/flow-nodes/src/StartNode/index.tsx | 44 ++----- .../flow-nodes/src/StartNode/metadata.tsx | 4 +- .../src/_/components/FlowCanvas.tsx | 87 ++++++++++--- .../src/_/components/FlowNodeHandles.tsx | 39 ++++++ .../src/_/components/FlowNodeWrapper.tsx | 106 +++++++++++++++ packages/flow-nodes/src/_/hooks/index.ts | 1 + .../flow-nodes/src/_/hooks/useFlowNodeId.ts | 5 + packages/flow-nodes/src/_/styles/index.ts | 25 ++-- packages/flow-nodes/src/_/types/index.ts | 16 +++ packages/flow-nodes/src/index.ts | 9 ++ 32 files changed, 818 insertions(+), 91 deletions(-) create mode 100644 packages/core/src/flow-node/types.ts create mode 100644 packages/flow-nodes/src/BranchNode/CaseBlock.tsx create mode 100644 packages/flow-nodes/src/BranchNode/constants.ts create mode 100644 packages/flow-nodes/src/BranchNode/demo.tsx create mode 100644 packages/flow-nodes/src/BranchNode/index.md create mode 100644 packages/flow-nodes/src/BranchNode/index.tsx create mode 100644 packages/flow-nodes/src/BranchNode/metadata.tsx create mode 100644 packages/flow-nodes/src/LooptNode/demo.tsx create mode 100644 packages/flow-nodes/src/LooptNode/index.md create mode 100644 packages/flow-nodes/src/LooptNode/index.tsx create mode 100644 packages/flow-nodes/src/LooptNode/metadata.tsx create mode 100644 packages/flow-nodes/src/RunScriptNode/demo.tsx create mode 100644 packages/flow-nodes/src/RunScriptNode/index.md create mode 100644 packages/flow-nodes/src/RunScriptNode/index.tsx create mode 100644 packages/flow-nodes/src/RunScriptNode/metadata.tsx create mode 100644 packages/flow-nodes/src/_/components/FlowNodeHandles.tsx create mode 100644 packages/flow-nodes/src/_/components/FlowNodeWrapper.tsx create mode 100644 packages/flow-nodes/src/_/hooks/index.ts create mode 100644 packages/flow-nodes/src/_/hooks/useFlowNodeId.ts diff --git a/packages/code-editor/src/CodeEditor/index.tsx b/packages/code-editor/src/CodeEditor/index.tsx index a94f0b6..6a23611 100644 --- a/packages/code-editor/src/CodeEditor/index.tsx +++ b/packages/code-editor/src/CodeEditor/index.tsx @@ -49,6 +49,7 @@ interface CodeEditorProps { onChange: (value: string) => void value: string getDataTreeDefs?: () => MDTernDefs + mode: CodeEditorModeEnum } export const CodeEditor: FC< @@ -59,6 +60,7 @@ export const CodeEditor: FC< > = (_props) => { const props: typeof _props = { ..._props, + mode: _props.mode || CodeEditorModeEnum.TextWithJs, getDataTreeDefs: _props.getDataTreeDefs ?? (() => ({})), hinting: _props.hinting ?? [bindingHint], ...mock_code_editor_props, @@ -175,7 +177,7 @@ export const CodeEditor: FC< autoRefresh: true, viewportMargin: 10, value: props.value, - mode: CodeEditorModeEnum.TextWithJs, + mode: props.mode, tabindex: -1, tabSize: 2, autoCloseBrackets: true, diff --git a/packages/code-editor/src/index.ts b/packages/code-editor/src/index.ts index 0b90787..3231664 100644 --- a/packages/code-editor/src/index.ts +++ b/packages/code-editor/src/index.ts @@ -1 +1,3 @@ +export { CodeEditorModeEnum } from './CodeEditor/common/editor-config' + export { CodeEditor } from './CodeEditor' diff --git a/packages/core/package.json b/packages/core/package.json index f1622fe..551302e 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -2,7 +2,7 @@ "name": "@modou/core", "version": "1.0.0", "description": "", - "main": "src/index.ts", + "main": "src", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, diff --git a/packages/core/src/flow-node/FlowNodeMetadata.ts b/packages/core/src/flow-node/FlowNodeMetadata.ts index 9dece9d..4595548 100644 --- a/packages/core/src/flow-node/FlowNodeMetadata.ts +++ b/packages/core/src/flow-node/FlowNodeMetadata.ts @@ -1,7 +1,14 @@ import { mapValues } from 'lodash' import { ReactNode } from 'react' -import { MRScheme, MRTypeAny, mr } from '@modou/refine' +import { + JsonSchema7ObjectType, + MRScheme, + MRTypeAny, + mr, + mrToJsonSchema, + schemeToJsonDefault, +} from '@modou/refine' import { MRArraySetterType, MRBooleanSetterType, @@ -12,6 +19,8 @@ import { } from '@modou/setters' import { MDVersion } from '../types' +import { generateId } from '../utils' +import { FlowNodeBaseProps, FlowNodePortNameEnum } from './types' // TODO 合并 Widget 类型定义 export interface MRFlowNodeProps { @@ -47,6 +56,9 @@ export class FlowNodeMetadata this.name = name this.version = version this.mrPropsScheme = mrPropsScheme + this.jsonPropsSchema = mrToJsonSchema( + mrPropsScheme, + ) as unknown as JsonSchema7ObjectType } type @@ -54,6 +66,7 @@ export class FlowNodeMetadata name version mrPropsScheme + jsonPropsSchema: JsonSchema7ObjectType static createMetadata( metadata: BaseFlowNodeMetadata, @@ -65,10 +78,12 @@ export class FlowNodeMetadata name, type, props, + defaultSources, }: { name: string type: string props: T + defaultSources?: Array<{ name: string }> }) { type PropsRawShape = { [K in keyof S]: S[K]['def'] @@ -87,22 +102,44 @@ export class FlowNodeMetadata type: mr.literal(type), name: mr.literal(name), position: mr.object({ - x: mr.number(), - y: mr.number(), + x: mr.number().default(100), + y: mr.number().default(100), }), - sources: mr.array( - mr.object({ - name: mr.string(), - id: mr.string(), - }), - ), - targets: mr.array( - mr.object({ - name: mr.string(), - id: mr.string(), - }), - ), + // 作为 source + sources: mr + .array( + mr.object({ + name: mr.string(), + }), + ) + .default( + defaultSources ?? [ + { + name: FlowNodePortNameEnum.SOURCE, + }, + ], + ), + // 作为 target + targets: mr + .array( + mr.object({ + name: mr.string(), + }), + ) + .default([ + { + name: FlowNodePortNameEnum.TARGET, + }, + ]), props: mr.object(propsRawShape), }) } + + static mrSchemeToDefaultJson( + scheme: Parameters[0], + ): FlowNodeBaseProps { + const props = schemeToJsonDefault(scheme) as unknown as FlowNodeBaseProps + props.id = generateId() + return props + } } diff --git a/packages/core/src/flow-node/index.ts b/packages/core/src/flow-node/index.ts index 6786214..c477abf 100644 --- a/packages/core/src/flow-node/index.ts +++ b/packages/core/src/flow-node/index.ts @@ -1 +1,2 @@ export * from './FlowNodeMetadata' +export * from './types' diff --git a/packages/core/src/flow-node/types.ts b/packages/core/src/flow-node/types.ts new file mode 100644 index 0000000..ad1f3d9 --- /dev/null +++ b/packages/core/src/flow-node/types.ts @@ -0,0 +1,11 @@ +import { mr } from '@modou/refine' + +import { FlowNodeMetadata, MRFlowNodeProps } from './FlowNodeMetadata' + +export type FlowNodeBaseProps = mr.infer< + ReturnType> +> +export enum FlowNodePortNameEnum { + SOURCE = 'SOURCE', + TARGET = 'TARGET', +} diff --git a/packages/flow-nodes/src/BranchNode/CaseBlock.tsx b/packages/flow-nodes/src/BranchNode/CaseBlock.tsx new file mode 100644 index 0000000..9910007 --- /dev/null +++ b/packages/flow-nodes/src/BranchNode/CaseBlock.tsx @@ -0,0 +1,122 @@ +import { DeleteOutlined } from '@ant-design/icons' +import { Button, Space } from 'antd' +import { FC, useMemo } from 'react' +import { Handle, Position } from 'reactflow' + +import { CodeEditor, CodeEditorModeEnum } from '@modou/code-editor' +import { cx, mcss } from '@modou/css-in-js' + +import { nodeClasses } from '../_/styles' +import { DEFAULT_LASE_ELSE_SCRIPT } from './constants' + +interface Branch { + script: string + port: string +} +export const CaseBlock: FC<{ + branch: Branch + onChangeBranch: (branch: Branch) => void + onDeleteBranch: (branch: Branch) => void + isHead: boolean + isLast: boolean + onlyOne: boolean +}> = ({ branch, isHead, isLast, onChangeBranch, onlyOne, onDeleteBranch }) => { + const hiddenCodeEditor = useMemo(() => { + return isLast && branch.script === DEFAULT_LASE_ELSE_SCRIPT + }, [branch.script, isLast]) + return ( +
+
+ {isHead &&
If
} + {!isHead && !isLast &&
Else If
} + {!onlyOne && isLast && ( +
+ + { + onChangeBranch({ + ...branch, + script: DEFAULT_LASE_ELSE_SCRIPT, + }) + }} + > + Else + + { + onChangeBranch({ + ...branch, + script: '', + }) + }} + > + Else If + + +
+ )} + + {!onlyOne && ( + + )} +
+ {!hiddenCodeEditor && ( +
+ { + onChangeBranch({ + ...branch, + script: value, + }) + }} + /> +
+ )} + +
+ ) +} + +const classes = { + wrapper: mcss` + background-color: rgba(0,0,0,.08); + border-radius: 6px; + padding: 6px; + position: relative; + `, + header: mcss` + margin-bottom: 4px; + display: flex; + align-items: center; + justify-content: space-between; + `, + label: mcss` + font-weight: bold; + .inactive{ + color: #888888; + } + `, + sourcePort: mcss` + right: -21px!important; + `, +} diff --git a/packages/flow-nodes/src/BranchNode/constants.ts b/packages/flow-nodes/src/BranchNode/constants.ts new file mode 100644 index 0000000..e213201 --- /dev/null +++ b/packages/flow-nodes/src/BranchNode/constants.ts @@ -0,0 +1 @@ +export const DEFAULT_LASE_ELSE_SCRIPT = '1===1&&66&77&&true' diff --git a/packages/flow-nodes/src/BranchNode/demo.tsx b/packages/flow-nodes/src/BranchNode/demo.tsx new file mode 100644 index 0000000..08ebcd6 --- /dev/null +++ b/packages/flow-nodes/src/BranchNode/demo.tsx @@ -0,0 +1,10 @@ +import { FC } from 'react' + +import { BranchNode, branchNodeNodeMetadata } from '@modou/flow-nodes' + +import { FlowCanvas } from '../_/components/FlowCanvas' + +const Demo: FC = () => { + return +} +export default Demo diff --git a/packages/flow-nodes/src/BranchNode/index.md b/packages/flow-nodes/src/BranchNode/index.md new file mode 100644 index 0000000..a040f76 --- /dev/null +++ b/packages/flow-nodes/src/BranchNode/index.md @@ -0,0 +1,5 @@ +# BranchNode + +执行脚本节点 + + diff --git a/packages/flow-nodes/src/BranchNode/index.tsx b/packages/flow-nodes/src/BranchNode/index.tsx new file mode 100644 index 0000000..af9c662 --- /dev/null +++ b/packages/flow-nodes/src/BranchNode/index.tsx @@ -0,0 +1,121 @@ +import { Button, Space } from 'antd' +import { type FC, memo } from 'react' +import { NodeProps } from 'reactflow' + +import { generateId } from '@modou/core' +import { mr } from '@modou/refine' + +import { FlowNodeHandles } from '../_/components/FlowNodeHandles' +import { FlowNodeWrapper } from '../_/components/FlowNodeWrapper' +import { useFlowNodeId } from '../_/hooks' +import { FlowNodeProps } from '../_/types' +import { CaseBlock } from './CaseBlock' +import { DEFAULT_LASE_ELSE_SCRIPT } from './constants' +import { MRSchemeBranchNodeProps, branchNodeNodeMetadata } from './metadata' + +const _BranchNode: FC< + NodeProps>> +> = (props) => { + const id = useFlowNodeId() + console.log('_BranchNode') + + return ( + <> + + + {props.data.props.branches.map((branch, index, branches) => ( + { + props.data._onChangeNode({ + id, + data: { + ...props.data, + props: { + ...props.data.props, + branches: props.data.props.branches.map((br) => { + if (br.port !== branch.port) { + return br + } + return branch + }), + }, + }, + }) + }} + onDeleteBranch={(branch) => { + // TODO 删除 branch 的同时删除相关的边 + props.data._onChangeNode({ + id, + data: { + ...props.data, + props: { + ...props.data.props, + branches: props.data.props.branches + .filter((br) => br.port !== branch.port) + .map((br, index) => { + if ( + index === 0 && + br.script === DEFAULT_LASE_ELSE_SCRIPT + ) { + return { + ...br, + script: '', + } + } + return br + }), + }, + sources: props.data.sources.filter( + (s) => s.name !== branch.port, + ), + }, + }) + }} + /> + ))} + + + + + + ) +} +export const BranchNode = memo(_BranchNode) diff --git a/packages/flow-nodes/src/BranchNode/metadata.tsx b/packages/flow-nodes/src/BranchNode/metadata.tsx new file mode 100644 index 0000000..98e059c --- /dev/null +++ b/packages/flow-nodes/src/BranchNode/metadata.tsx @@ -0,0 +1,37 @@ +import { AndroidOutlined } from '@ant-design/icons' + +import { FlowNodeMetadata, FlowNodePortNameEnum } from '@modou/core' +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import { mr } from '@modou/refine' + +import { FlowNodeEnum } from '../_/types' + +export const MRSchemeBranchNodeProps = FlowNodeMetadata.createMRFlowNodeProps({ + type: FlowNodeEnum.BRANCH_NODE, + name: '条件分支', + props: { + branches: { + def: mr + .array( + mr.object({ + script: mr.string().default(''), + port: mr.string(), + }), + ) + .default([ + { + script: '', + port: FlowNodePortNameEnum.SOURCE, + }, + ]), + }, + }, +}) + +export const branchNodeNodeMetadata = FlowNodeMetadata.createMetadata({ + version: '0.0.1', + type: FlowNodeEnum.BRANCH_NODE, + name: '条件分支', + icon: , + mrPropsScheme: MRSchemeBranchNodeProps, +}) diff --git a/packages/flow-nodes/src/LooptNode/demo.tsx b/packages/flow-nodes/src/LooptNode/demo.tsx new file mode 100644 index 0000000..ac847a5 --- /dev/null +++ b/packages/flow-nodes/src/LooptNode/demo.tsx @@ -0,0 +1,10 @@ +import { FC } from 'react' + +import { LoopNode, loopNodeMetadata } from '@modou/flow-nodes' + +import { FlowCanvas } from '../_/components/FlowCanvas' + +const Demo: FC = () => { + return +} +export default Demo diff --git a/packages/flow-nodes/src/LooptNode/index.md b/packages/flow-nodes/src/LooptNode/index.md new file mode 100644 index 0000000..ff0a944 --- /dev/null +++ b/packages/flow-nodes/src/LooptNode/index.md @@ -0,0 +1,5 @@ +# LoopNode + +循环节点 + + diff --git a/packages/flow-nodes/src/LooptNode/index.tsx b/packages/flow-nodes/src/LooptNode/index.tsx new file mode 100644 index 0000000..9aa0af7 --- /dev/null +++ b/packages/flow-nodes/src/LooptNode/index.tsx @@ -0,0 +1,43 @@ +import { type FC, memo } from 'react' +import { NodeProps, useReactFlow } from 'reactflow' + +import { CodeEditor, CodeEditorModeEnum } from '@modou/code-editor' +import { mr } from '@modou/refine' + +import { FlowNodeHandles } from '../_/components/FlowNodeHandles' +import { FlowNodeWrapper } from '../_/components/FlowNodeWrapper' +import { useFlowNodeId } from '../_/hooks' +import { FlowNodeProps } from '../_/types' +import { MRSchemeLoopNodeProps, loopNodeMetadata } from './metadata' + +type LoopNodeProps = mr.infer +const _LoopNode: FC>> = (props) => { + const id = useFlowNodeId() + return ( + <> + +
+
循环体
+ { + props.data._onChangeNode({ + id, + data: { + ...props.data, + props: { + ...props.data.props, + iterable: value, + }, + }, + }) + }} + /> +
+
+ + + ) +} +export const LoopNode = memo(_LoopNode) diff --git a/packages/flow-nodes/src/LooptNode/metadata.tsx b/packages/flow-nodes/src/LooptNode/metadata.tsx new file mode 100644 index 0000000..a767dc6 --- /dev/null +++ b/packages/flow-nodes/src/LooptNode/metadata.tsx @@ -0,0 +1,33 @@ +import { AndroidOutlined } from '@ant-design/icons' + +import { FlowNodeMetadata, FlowNodePortNameEnum } from '@modou/core' +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import { mr } from '@modou/refine' + +import { FlowNodeEnum, ScopedFlowNodePortNameEnum } from '../_/types' + +export const MRSchemeLoopNodeProps = FlowNodeMetadata.createMRFlowNodeProps({ + type: FlowNodeEnum.LOOP_NODE, + name: '循环', + defaultSources: [ + { + name: FlowNodePortNameEnum.SOURCE, + }, + { + name: ScopedFlowNodePortNameEnum.LOOP_BODY, + }, + ], + props: { + iterable: { + def: mr.string().default(''), + }, + }, +}) + +export const loopNodeMetadata = FlowNodeMetadata.createMetadata({ + version: '0.0.1', + type: FlowNodeEnum.LOOP_NODE, + name: '循环', + icon: , + mrPropsScheme: MRSchemeLoopNodeProps, +}) diff --git a/packages/flow-nodes/src/RunScriptNode/demo.tsx b/packages/flow-nodes/src/RunScriptNode/demo.tsx new file mode 100644 index 0000000..b0938ac --- /dev/null +++ b/packages/flow-nodes/src/RunScriptNode/demo.tsx @@ -0,0 +1,12 @@ +import { FC } from 'react' + +import { RunScriptNode, runScriptNodeNodeMetadata } from '@modou/flow-nodes' + +import { FlowCanvas } from '../_/components/FlowCanvas' + +const Demo: FC = () => { + return ( + + ) +} +export default Demo diff --git a/packages/flow-nodes/src/RunScriptNode/index.md b/packages/flow-nodes/src/RunScriptNode/index.md new file mode 100644 index 0000000..f0180a4 --- /dev/null +++ b/packages/flow-nodes/src/RunScriptNode/index.md @@ -0,0 +1,5 @@ +# RunScriptNode + +执行脚本节点 + + diff --git a/packages/flow-nodes/src/RunScriptNode/index.tsx b/packages/flow-nodes/src/RunScriptNode/index.tsx new file mode 100644 index 0000000..17eb883 --- /dev/null +++ b/packages/flow-nodes/src/RunScriptNode/index.tsx @@ -0,0 +1,49 @@ +import { type FC, memo } from 'react' +import { NodeProps } from 'reactflow' + +import { CodeEditor, CodeEditorModeEnum } from '@modou/code-editor' +import { mr } from '@modou/refine' + +import { FlowNodeHandles } from '../_/components/FlowNodeHandles' +import { FlowNodeWrapper } from '../_/components/FlowNodeWrapper' +import { useFlowNodeId } from '../_/hooks' +import { FlowNodeProps } from '../_/types' +import { + MRSchemeRunScriptNodeProps, + runScriptNodeNodeMetadata, +} from './metadata' + +const _RunScriptNode: FC< + NodeProps>> +> = (props) => { + const id = useFlowNodeId() + console.log('_RunScriptNode') + + return ( + <> + + { + props.data._onChangeNode({ + id, + data: { + ...props.data, + props: { + ...props.data.props, + props: { + ...props.data.props, + script: value, + }, + }, + }, + }) + }} + /> + + + + ) +} +export const RunScriptNode = memo(_RunScriptNode) diff --git a/packages/flow-nodes/src/RunScriptNode/metadata.tsx b/packages/flow-nodes/src/RunScriptNode/metadata.tsx new file mode 100644 index 0000000..ed2f60e --- /dev/null +++ b/packages/flow-nodes/src/RunScriptNode/metadata.tsx @@ -0,0 +1,26 @@ +import { AndroidOutlined } from '@ant-design/icons' + +import { FlowNodeMetadata } from '@modou/core' +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import { mr } from '@modou/refine' + +import { FlowNodeEnum } from '../_/types' + +export const MRSchemeRunScriptNodeProps = + FlowNodeMetadata.createMRFlowNodeProps({ + type: FlowNodeEnum.RUN_SCRIPT_NODE, + name: '执行脚本', + props: { + script: { + def: mr.string().default(''), + }, + }, + }) + +export const runScriptNodeNodeMetadata = FlowNodeMetadata.createMetadata({ + version: '0.0.1', + type: FlowNodeEnum.RUN_SCRIPT_NODE, + name: '执行脚本', + icon: , + mrPropsScheme: MRSchemeRunScriptNodeProps, +}) diff --git a/packages/flow-nodes/src/StartNode/demo.tsx b/packages/flow-nodes/src/StartNode/demo.tsx index 798adb8..1cdec3f 100644 --- a/packages/flow-nodes/src/StartNode/demo.tsx +++ b/packages/flow-nodes/src/StartNode/demo.tsx @@ -1,10 +1,10 @@ import { FC } from 'react' -import { StartNode } from '@modou/flow-nodes' +import { StartNode, startNodeMetadata } from '@modou/flow-nodes' import { FlowCanvas } from '../_/components/FlowCanvas' const Demo: FC = () => { - return + return } export default Demo diff --git a/packages/flow-nodes/src/StartNode/index.md b/packages/flow-nodes/src/StartNode/index.md index cad553a..76a674b 100644 --- a/packages/flow-nodes/src/StartNode/index.md +++ b/packages/flow-nodes/src/StartNode/index.md @@ -1,6 +1,5 @@ # StartNode -This is an example component. - +开始节点 diff --git a/packages/flow-nodes/src/StartNode/index.tsx b/packages/flow-nodes/src/StartNode/index.tsx index f2b8231..9cf4c1d 100644 --- a/packages/flow-nodes/src/StartNode/index.tsx +++ b/packages/flow-nodes/src/StartNode/index.tsx @@ -1,45 +1,19 @@ import { type FC, memo } from 'react' -import { Handle, NodeProps, Position } from 'reactflow' +import { NodeProps } from 'reactflow' -import { cx, mcss } from '@modou/css-in-js' +import { FlowNodeHandles } from '../_/components/FlowNodeHandles' +import { FlowNodeWrapper } from '../_/components/FlowNodeWrapper' +import { FlowNodeProps } from '../_/types' +import { startNodeMetadata } from './metadata' -import { nodeClasses } from '../_/styles' - -const _StartNode: FC> = ({ isConnectable }) => { +const _StartNode: FC> = (props) => { return ( <> -
-
Wrapper Header
-
Wrapper Body
-
- - - + + ) } export const StartNode = memo(_StartNode) -const classes = { - wrapper: mcss` - `, -} +const classes = {} diff --git a/packages/flow-nodes/src/StartNode/metadata.tsx b/packages/flow-nodes/src/StartNode/metadata.tsx index 1c09b1f..0a7031b 100644 --- a/packages/flow-nodes/src/StartNode/metadata.tsx +++ b/packages/flow-nodes/src/StartNode/metadata.tsx @@ -1,3 +1,5 @@ +import { AndroidOutlined } from '@ant-design/icons' + import { FlowNodeMetadata } from '@modou/core' // eslint-disable-next-line @typescript-eslint/no-unused-vars import { mr } from '@modou/refine' @@ -14,6 +16,6 @@ export const startNodeMetadata = FlowNodeMetadata.createMetadata({ version: '0.0.1', type: FlowNodeEnum.START_NODE, name: '开始', - icon:
ICON
, + icon: , mrPropsScheme: MRSchemeStartNodeProps, }) diff --git a/packages/flow-nodes/src/_/components/FlowCanvas.tsx b/packages/flow-nodes/src/_/components/FlowCanvas.tsx index 1daabfa..a136af6 100644 --- a/packages/flow-nodes/src/_/components/FlowCanvas.tsx +++ b/packages/flow-nodes/src/_/components/FlowCanvas.tsx @@ -1,4 +1,11 @@ -import { ComponentProps, ComponentType, FC, useCallback, useMemo } from 'react' +import { + ComponentProps, + ComponentType, + FC, + useCallback, + useEffect, + useMemo, +} from 'react' import ReactFlow, { Background, Controls, @@ -12,27 +19,66 @@ import ReactFlow, { } from 'reactflow' import 'reactflow/dist/style.css' +import { FlowNodeMetadata } from '@modou/core' import { mcss } from '@modou/css-in-js' -const _FlowCanvas: FC<{ flowNode: ComponentType }> = ({ flowNode }) => { +import { FlowNodeProps, OnChangeNode } from '../types' + +const _FlowCanvas: FC<{ + flowNode: ComponentType + meta: FlowNodeMetadata +}> = ({ flowNode, meta }) => { const reactFlowInstance = useReactFlow() - const [nodes] = useNodesState([ - { - id: 'demo_id', - type: 'DEMO', - data: {}, - position: { x: 100, y: 100 }, - }, - { - id: 'demo_demo', - data: {}, - position: { x: 500, y: 500 }, - }, - ]) + const [nodes, setNodes] = useNodesState([]) const [edges, setEdges] = useEdgesState([]) + useEffect(() => { + const defaultProps = FlowNodeMetadata.mrSchemeToDefaultJson( + meta.jsonPropsSchema, + ) + + const _onChangeNode: OnChangeNode = (node) => { + setNodes((nds) => + nds.map((nd) => { + if (nd.id !== node.id) { + return nd + } + return { + ...nd, + ...node, + } + }), + ) + } + + setNodes([ + { + id: defaultProps.id, + type: defaultProps.type, + data: { + ...defaultProps, + _onChangeNode, + }, + position: defaultProps.position, + }, + { + id: 'demo_demo', + data: { + name: 'demo', + id: 'demo_demo', + type: 'demo', + sources: [], + targets: [], + position: { x: 500, y: 500 }, + _onChangeNode, + } as any, + position: { x: 500, y: 500 }, + }, + ]) + }, []) + const onConnect = useCallback( (params) => setEdges((eds) => @@ -41,7 +87,14 @@ const _FlowCanvas: FC<{ flowNode: ComponentType }> = ({ flowNode }) => { [setEdges], ) - const nodeTypes: NodeTypes = useMemo(() => ({ DEMO: flowNode }), [flowNode]) + const nodeTypes: NodeTypes = useMemo( + () => ({ [meta.type]: flowNode }), + [flowNode, meta.type], + ) + + useEffect(() => { + console.log('FlowCanvas 重新渲染了') + }) return (
@@ -56,7 +109,7 @@ const _FlowCanvas: FC<{ flowNode: ComponentType }> = ({ flowNode }) => { - + false} /> ) } diff --git a/packages/flow-nodes/src/LooptNode/index.tsx b/packages/flow-nodes/src/LooptNode/index.tsx index 9aa0af7..e6dd87f 100644 --- a/packages/flow-nodes/src/LooptNode/index.tsx +++ b/packages/flow-nodes/src/LooptNode/index.tsx @@ -1,5 +1,5 @@ -import { type FC, memo } from 'react' -import { NodeProps, useReactFlow } from 'reactflow' +import { type FC, memo, useMemo } from 'react' +import { Handle, NodeProps, Position, useReactFlow } from 'reactflow' import { CodeEditor, CodeEditorModeEnum } from '@modou/code-editor' import { mr } from '@modou/refine' @@ -7,12 +7,18 @@ import { mr } from '@modou/refine' import { FlowNodeHandles } from '../_/components/FlowNodeHandles' import { FlowNodeWrapper } from '../_/components/FlowNodeWrapper' import { useFlowNodeId } from '../_/hooks' -import { FlowNodeProps } from '../_/types' +import { nodeClasses } from '../_/styles' +import { FlowNodeProps, ScopedFlowNodePortNameEnum } from '../_/types' import { MRSchemeLoopNodeProps, loopNodeMetadata } from './metadata' type LoopNodeProps = mr.infer const _LoopNode: FC>> = (props) => { const id = useFlowNodeId() + const loopBodyPort = useMemo(() => { + return props.data.sources.find( + (s) => s.name === ScopedFlowNodePortNameEnum.LOOP_BODY, + )! + }, [props.data.sources]) return ( <> @@ -36,7 +42,20 @@ const _LoopNode: FC>> = (props) => { />
- + + port.name !== ScopedFlowNodePortNameEnum.LOOP_BODY + } + /> + ) } diff --git a/packages/flow-nodes/src/_/components/FlowNodeHandles.tsx b/packages/flow-nodes/src/_/components/FlowNodeHandles.tsx index a0b064c..5ab2e3b 100644 --- a/packages/flow-nodes/src/_/components/FlowNodeHandles.tsx +++ b/packages/flow-nodes/src/_/components/FlowNodeHandles.tsx @@ -1,4 +1,4 @@ -import { FC } from 'react' +import { FC, useMemo } from 'react' import { Handle, NodeProps, Position } from 'reactflow' import { nodeClasses } from '../styles' @@ -6,34 +6,44 @@ import { FlowNodeProps } from '../types' export const FlowNodeHandles: FC< NodeProps & { - hiddenTargets?: boolean - hiddenSources?: boolean + filterTargets?: (node: { name: string }) => boolean + filterSources?: (node: { name: string }) => boolean } -> = ({ data, isConnectable, hiddenTargets, hiddenSources }) => { +> = ({ data, isConnectable, filterTargets, filterSources }) => { + const targets = useMemo(() => { + if (!filterTargets) { + return data.targets + } + return data.targets.filter(filterTargets) + }, [data.targets, filterTargets]) + const sources = useMemo(() => { + if (!filterSources) { + return data.sources + } + return data.sources.filter(filterSources) + }, [data.sources, filterSources]) return ( <> - {!hiddenTargets && - data.targets.map((target) => ( - - ))} - {!hiddenSources && - data.sources.map((source) => ( - - ))} + {targets.map((target) => ( + + ))} + {sources.map((source) => ( + + ))} ) } diff --git a/packages/flow-nodes/src/_/components/FlowNodeWrapper.tsx b/packages/flow-nodes/src/_/components/FlowNodeWrapper.tsx index 1e68249..aedf775 100644 --- a/packages/flow-nodes/src/_/components/FlowNodeWrapper.tsx +++ b/packages/flow-nodes/src/_/components/FlowNodeWrapper.tsx @@ -2,7 +2,7 @@ import { Input } from 'antd' import { FC, ReactNode, useState } from 'react' import { NodeProps } from 'reactflow' -import { FlowNodeMetadata } from '@modou/core' +import { type FlowNodeMetadata } from '@modou/core' import { cx, mcss } from '@modou/css-in-js' import { useFlowNodeId } from '../hooks' @@ -21,7 +21,11 @@ export const FlowNodeWrapper: FC<{ const [nameMode, setNameMode] = useState(NameMode.Readonly) return (
-
+
{meta.icon}
@@ -82,6 +86,9 @@ const classes = { color: white; border-top-left-radius: 8px; border-top-right-radius: 8px; + &.all-border-radius{ + border-radius: 8px; + } `, headerLeft: mcss` display: flex; From 76be2ffce63cb8f638fdcd0dc34f6460c39f0dac Mon Sep 17 00:00:00 2001 From: liulei Date: Wed, 1 Feb 2023 09:52:30 +0800 Subject: [PATCH 59/68] =?UTF-8?q?feat(flow-node):=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=B5=81=E8=8A=82=E7=82=B9=E8=A7=A3=E9=87=8A=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + packages/evaluate/src/index.ts | 29 +++++++ packages/flow-nodes/src/BranchNode/demo.tsx | 21 ++++- packages/flow-nodes/src/BranchNode/index.tsx | 77 ++++++++----------- .../flow-nodes/src/BranchNode/interpreter.ts | 22 ++++++ packages/flow-nodes/src/LooptNode/index.tsx | 13 ++-- .../flow-nodes/src/RunScriptNode/demo.tsx | 21 ++++- .../flow-nodes/src/RunScriptNode/index.tsx | 21 ++--- .../src/RunScriptNode/interpreter.ts | 12 +++ .../flow-nodes/src/RunScriptNode/metadata.tsx | 2 +- .../src/_/components/FlowCanvas.tsx | 10 ++- packages/flow-nodes/src/_/types/index.ts | 6 ++ packages/render/src/utils/evaluate.ts | 27 ------- .../state-manager/src/WidgetState/index.ts | 2 +- pnpm-lock.yaml | 49 +++++++----- 15 files changed, 192 insertions(+), 121 deletions(-) create mode 100644 packages/flow-nodes/src/BranchNode/interpreter.ts create mode 100644 packages/flow-nodes/src/RunScriptNode/interpreter.ts delete mode 100644 packages/render/src/utils/evaluate.ts diff --git a/package.json b/package.json index 15745b4..5cb079a 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "axios": "^1.1.3", "flat": "^5.0.2", "handlebars": "^4.7.7", + "immer": "^9.0.19", "json-schema": "^0.4.0", "lodash": "^4.17.21", "mitt": "^3.0.0", diff --git a/packages/evaluate/src/index.ts b/packages/evaluate/src/index.ts index b30a0ed..570c921 100644 --- a/packages/evaluate/src/index.ts +++ b/packages/evaluate/src/index.ts @@ -3,3 +3,32 @@ const EXPRESSION_REG = /[\s\S]*{{[\s\S]*}}[\s\S]*/m export const isExpression = (str: unknown): str is string => { return typeof str === 'string' && EXPRESSION_REG.test(str) } +// TODO 完善 store 类型 +export const evalExpression = ( + expression: string, + state: Record, +) => { + try { + // eslint-disable-next-line @typescript-eslint/no-implied-eval,no-new-func,no-useless-call + return new Function( + 'state', + `with(state){ + return ${expression} + }`, + // TODO state 打平收集到 stateManager + ).call(null, state) + } catch (e) { + return String((e as SyntaxError)?.message) ?? 'Error' + } +} + +export const evalScript = (script: string, state: Record) => { + // eslint-disable-next-line @typescript-eslint/no-implied-eval,no-new-func,no-useless-call + return new Function( + 'state', + `with(state){ + ${script} + }`, + // TODO state 打平收集到 stateManager + ).call(null, state) +} diff --git a/packages/flow-nodes/src/BranchNode/demo.tsx b/packages/flow-nodes/src/BranchNode/demo.tsx index 08ebcd6..3f581b8 100644 --- a/packages/flow-nodes/src/BranchNode/demo.tsx +++ b/packages/flow-nodes/src/BranchNode/demo.tsx @@ -1,10 +1,27 @@ import { FC } from 'react' -import { BranchNode, branchNodeNodeMetadata } from '@modou/flow-nodes' +import { + BranchNode, + MRSchemeBranchNodeProps, + branchNodeNodeMetadata, +} from '@modou/flow-nodes' +import { mr } from '@modou/refine' import { FlowCanvas } from '../_/components/FlowCanvas' +import { FlowNodeProps } from '../_/types' +import { branchNodeInterpreter } from './interpreter' const Demo: FC = () => { - return + return ( + >, + ) => { + console.log(branchNodeInterpreter(props)) + }} + /> + ) } export default Demo diff --git a/packages/flow-nodes/src/BranchNode/index.tsx b/packages/flow-nodes/src/BranchNode/index.tsx index 0ed19c9..ef5a758 100644 --- a/packages/flow-nodes/src/BranchNode/index.tsx +++ b/packages/flow-nodes/src/BranchNode/index.tsx @@ -1,4 +1,5 @@ import { Button, Space } from 'antd' +import produce from 'immer' import { type FC, memo } from 'react' import { NodeProps } from 'reactflow' @@ -51,29 +52,25 @@ const _BranchNode: FC< // TODO 删除 branch 的同时删除相关的边 props.data._onChangeNode({ id, - data: { - ...props.data, - props: { - ...props.data.props, - branches: props.data.props.branches - .filter((br) => br.port !== branch.port) - .map((br, index) => { - if ( - index === 0 && - br.script === DEFAULT_LASE_ELSE_SCRIPT - ) { - return { - ...br, - script: '', - } + data: produce(props.data, (draft) => { + draft.props.branches = draft.props.branches + .filter((br) => br.port !== branch.port) + .map((br, index) => { + if ( + index === 0 && + br.script === DEFAULT_LASE_ELSE_SCRIPT + ) { + return { + ...br, + script: '', } - return br - }), - }, - sources: props.data.sources.filter( + } + return br + }) + draft.sources = draft.sources.filter( (s) => s.name !== branch.port, - ), - }, + ) + }), }) }} /> @@ -85,28 +82,22 @@ const _BranchNode: FC< const portId = generateId() props.data._onChangeNode({ id, - data: { - ...props.data, - sources: [ - ...props.data.sources, - { - name: portId, - }, - ], - props: { - ...props.data.props, - branches: [ - ...props.data.props.branches.map((branch) => ({ - ...branch, - script: '', - })), - { - port: portId, - script: DEFAULT_LASE_ELSE_SCRIPT, - }, - ], - }, - }, + data: produce(props.data, (draft) => { + draft.sources.push({ + name: portId, + }) + draft.props.branches = draft.props.branches.map((branch) => ({ + ...branch, + script: + branch.script === DEFAULT_LASE_ELSE_SCRIPT + ? '' + : branch.script, + })) + draft.props.branches.push({ + port: portId, + script: DEFAULT_LASE_ELSE_SCRIPT, + }) + }), }) }} > diff --git a/packages/flow-nodes/src/BranchNode/interpreter.ts b/packages/flow-nodes/src/BranchNode/interpreter.ts new file mode 100644 index 0000000..b189a7e --- /dev/null +++ b/packages/flow-nodes/src/BranchNode/interpreter.ts @@ -0,0 +1,22 @@ +import { evalScript } from '@modou/evaluate' +import { MRSchemeBranchNodeProps } from '@modou/flow-nodes' +import { mr } from '@modou/refine' + +import { FlowNodeInterpreter } from '../_/types' + +export const branchNodeInterpreter: FlowNodeInterpreter< + mr.infer +> = (props) => { + // 1、迭代条件 + // 2、找到为真的条件 + // 3、找到为真的条件对应的 source port + // 4、找到 source port 对应的 target node + // 5、执行target node + // 返回 + const branches = props.props.branches + for (const branch of branches) { + if (evalScript(`return ${branch.script}`, {})) { + return + } + } +} diff --git a/packages/flow-nodes/src/LooptNode/index.tsx b/packages/flow-nodes/src/LooptNode/index.tsx index e6dd87f..1a27329 100644 --- a/packages/flow-nodes/src/LooptNode/index.tsx +++ b/packages/flow-nodes/src/LooptNode/index.tsx @@ -1,5 +1,6 @@ +import produce from 'immer' import { type FC, memo, useMemo } from 'react' -import { Handle, NodeProps, Position, useReactFlow } from 'reactflow' +import { Handle, NodeProps, Position } from 'reactflow' import { CodeEditor, CodeEditorModeEnum } from '@modou/code-editor' import { mr } from '@modou/refine' @@ -30,13 +31,9 @@ const _LoopNode: FC>> = (props) => { onChange={(value) => { props.data._onChangeNode({ id, - data: { - ...props.data, - props: { - ...props.data.props, - iterable: value, - }, - }, + data: produce(props.data, (draft) => { + draft.props.iterable = value + }), }) }} /> diff --git a/packages/flow-nodes/src/RunScriptNode/demo.tsx b/packages/flow-nodes/src/RunScriptNode/demo.tsx index b0938ac..3fd46e6 100644 --- a/packages/flow-nodes/src/RunScriptNode/demo.tsx +++ b/packages/flow-nodes/src/RunScriptNode/demo.tsx @@ -1,12 +1,29 @@ import { FC } from 'react' -import { RunScriptNode, runScriptNodeNodeMetadata } from '@modou/flow-nodes' +import { + MRSchemeRunScriptNodeProps, + RunScriptNode, + runScriptNodeMetadata, +} from '@modou/flow-nodes' +import { mr } from '@modou/refine' import { FlowCanvas } from '../_/components/FlowCanvas' +import { FlowNodeProps } from '../_/types' +import { runScriptNodeInterpreter } from './interpreter' const Demo: FC = () => { return ( - + <> + >, + ) => { + console.log(runScriptNodeInterpreter(props)) + }} + /> + ) } export default Demo diff --git a/packages/flow-nodes/src/RunScriptNode/index.tsx b/packages/flow-nodes/src/RunScriptNode/index.tsx index 17eb883..82ee96e 100644 --- a/packages/flow-nodes/src/RunScriptNode/index.tsx +++ b/packages/flow-nodes/src/RunScriptNode/index.tsx @@ -1,3 +1,4 @@ +import produce from 'immer' import { type FC, memo } from 'react' import { NodeProps } from 'reactflow' @@ -8,10 +9,7 @@ import { FlowNodeHandles } from '../_/components/FlowNodeHandles' import { FlowNodeWrapper } from '../_/components/FlowNodeWrapper' import { useFlowNodeId } from '../_/hooks' import { FlowNodeProps } from '../_/types' -import { - MRSchemeRunScriptNodeProps, - runScriptNodeNodeMetadata, -} from './metadata' +import { MRSchemeRunScriptNodeProps, runScriptNodeMetadata } from './metadata' const _RunScriptNode: FC< NodeProps>> @@ -21,23 +19,16 @@ const _RunScriptNode: FC< return ( <> - + { props.data._onChangeNode({ id, - data: { - ...props.data, - props: { - ...props.data.props, - props: { - ...props.data.props, - script: value, - }, - }, - }, + data: produce(props.data, (draft) => { + draft.props.script = value + }), }) }} /> diff --git a/packages/flow-nodes/src/RunScriptNode/interpreter.ts b/packages/flow-nodes/src/RunScriptNode/interpreter.ts new file mode 100644 index 0000000..d36530e --- /dev/null +++ b/packages/flow-nodes/src/RunScriptNode/interpreter.ts @@ -0,0 +1,12 @@ +import { evalScript } from '@modou/evaluate' +import { MRSchemeRunScriptNodeProps } from '@modou/flow-nodes' +import { mr } from '@modou/refine' + +import { FlowNodeInterpreter } from '../_/types' + +export const runScriptNodeInterpreter: FlowNodeInterpreter< + mr.infer +> = (props) => { + const script = props.props.script + return evalScript(script, {}) +} diff --git a/packages/flow-nodes/src/RunScriptNode/metadata.tsx b/packages/flow-nodes/src/RunScriptNode/metadata.tsx index ed2f60e..6e4e866 100644 --- a/packages/flow-nodes/src/RunScriptNode/metadata.tsx +++ b/packages/flow-nodes/src/RunScriptNode/metadata.tsx @@ -17,7 +17,7 @@ export const MRSchemeRunScriptNodeProps = }, }) -export const runScriptNodeNodeMetadata = FlowNodeMetadata.createMetadata({ +export const runScriptNodeMetadata = FlowNodeMetadata.createMetadata({ version: '0.0.1', type: FlowNodeEnum.RUN_SCRIPT_NODE, name: '执行脚本', diff --git a/packages/flow-nodes/src/_/components/FlowCanvas.tsx b/packages/flow-nodes/src/_/components/FlowCanvas.tsx index a136af6..4dd1476 100644 --- a/packages/flow-nodes/src/_/components/FlowCanvas.tsx +++ b/packages/flow-nodes/src/_/components/FlowCanvas.tsx @@ -27,7 +27,8 @@ import { FlowNodeProps, OnChangeNode } from '../types' const _FlowCanvas: FC<{ flowNode: ComponentType meta: FlowNodeMetadata -}> = ({ flowNode, meta }) => { + runInterpreter: (props: FlowNodeProps) => void +}> = ({ flowNode, meta, runInterpreter }) => { const reactFlowInstance = useReactFlow() const [nodes, setNodes] = useNodesState([]) @@ -121,6 +122,13 @@ const _FlowCanvas: FC<{ > GetEdges +
) } diff --git a/packages/flow-nodes/src/_/types/index.ts b/packages/flow-nodes/src/_/types/index.ts index 46110d3..002dd5f 100644 --- a/packages/flow-nodes/src/_/types/index.ts +++ b/packages/flow-nodes/src/_/types/index.ts @@ -2,6 +2,8 @@ import { Node } from 'reactflow' import { FlowNodeBaseProps } from '@modou/core/src/flow-node/types' +import { branchNodeInterpreter } from '../../BranchNode/interpreter' + export enum FlowNodeEnum { // 开始 START_NODE = 'START_NODE', @@ -31,3 +33,7 @@ export type FlowNodeProps = export type OnChangeNode = ( node: Partial> & { id: string }, ) => void + +export type FlowNodeInterpreter

= ( + props: P, +) => void diff --git a/packages/render/src/utils/evaluate.ts b/packages/render/src/utils/evaluate.ts deleted file mode 100644 index aa387bc..0000000 --- a/packages/render/src/utils/evaluate.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { mapValues } from 'lodash' - -import { PageState } from '@modou/state-manager' - -const EXPRESSION_REG = /[\s\S]*{{[\s\S]*}}[\s\S]*/m - -export const isExpression = (str: unknown): str is string => { - return typeof str === 'string' && EXPRESSION_REG.test(str) -} -// TODO 完善 store 类型 -export const evalExpression = ( - expression: string, - state: Record, -) => { - try { - // eslint-disable-next-line @typescript-eslint/no-implied-eval,no-new-func,no-useless-call - return new Function( - 'state', - `with(state){ - return ${expression} - }`, - // TODO state 打平收集到 stateManager - ).call(null, state) - } catch (e) { - return String((e as SyntaxError)?.message) ?? 'Error' - } -} diff --git a/packages/state-manager/src/WidgetState/index.ts b/packages/state-manager/src/WidgetState/index.ts index b7adb53..3ffa81f 100644 --- a/packages/state-manager/src/WidgetState/index.ts +++ b/packages/state-manager/src/WidgetState/index.ts @@ -14,6 +14,7 @@ import { } from 'lodash' import { AppFactory } from '@modou/core' +import { evalExpression } from '@modou/evaluate' import { WidgetFile } from '@modou/meta-vfs' import { IReactionDisposer, @@ -24,7 +25,6 @@ import { runInAction, toJS, } from '@modou/reactivity' -import { evalExpression } from '@modou/render/src/utils/evaluate' import { PageState } from '../PageState' import { WidgetVariables } from '../contexts' diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7d76c16..b5dcf63 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -54,6 +54,7 @@ importers: eslint-plugin-react-hooks: ^4.6.0 flat: ^5.0.2 handlebars: ^4.7.7 + immer: ^9.0.19 json-schema: ^0.4.0 lodash: ^4.17.21 mitt: ^3.0.0 @@ -97,6 +98,7 @@ importers: axios: 1.1.3 flat: 5.0.2 handlebars: 4.7.7 + immer: 9.0.19 json-schema: 0.4.0 lodash: 4.17.21 mitt: 3.0.0 @@ -107,7 +109,7 @@ importers: react-dom: 18.2.0_react@18.2.0 react-json-view: 1.21.3_rj7ozvcq3uehdlnj3cbwzbi5ce react-router-dom: 6.4.2_biqbaboplfbrettd7655fr4n2y - reactflow: 11.5.1_biqbaboplfbrettd7655fr4n2y + reactflow: 11.5.1_ytuas6axp6gvse4ghxb2libdjm ts-pattern: 4.0.5 devDependencies: '@emotion/babel-plugin': 11.10.5 @@ -2878,28 +2880,28 @@ packages: resolution: {integrity: sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA==} dev: false - /@reactflow/background/11.1.3_biqbaboplfbrettd7655fr4n2y: + /@reactflow/background/11.1.3_ytuas6axp6gvse4ghxb2libdjm: resolution: {integrity: sha512-U5h43dobrdYy+PdczS3wZRjDphjYemH4VPKZoi5HCeWsevqHqFSmQE+GC8RNXmWxYObqUA9EGSWlfCtWSg0HKQ==} peerDependencies: react: '>=17' react-dom: '>=17' dependencies: - '@reactflow/core': 11.5.0_biqbaboplfbrettd7655fr4n2y + '@reactflow/core': 11.5.0_ytuas6axp6gvse4ghxb2libdjm classcat: 5.0.4 react: 18.2.0 react-dom: 18.2.0_react@18.2.0 - zustand: 4.3.2_react@18.2.0 + zustand: 4.3.2_immer@9.0.19+react@18.2.0 transitivePeerDependencies: - immer dev: false - /@reactflow/controls/11.1.3_biqbaboplfbrettd7655fr4n2y: + /@reactflow/controls/11.1.3_ytuas6axp6gvse4ghxb2libdjm: resolution: {integrity: sha512-lqh8Nymr+YzqhzjdXg5MhqhP2cZF5w+MErtB9aBUjAn/8zJbEz1bqzFxfmo/xFugtrK2ujW4HBix15zjv/6gzQ==} peerDependencies: react: '>=17' react-dom: '>=17' dependencies: - '@reactflow/core': 11.5.0_biqbaboplfbrettd7655fr4n2y + '@reactflow/core': 11.5.0_ytuas6axp6gvse4ghxb2libdjm classcat: 5.0.4 react: 18.2.0 react-dom: 18.2.0_react@18.2.0 @@ -2907,7 +2909,7 @@ packages: - immer dev: false - /@reactflow/core/11.5.0_biqbaboplfbrettd7655fr4n2y: + /@reactflow/core/11.5.0_ytuas6axp6gvse4ghxb2libdjm: resolution: {integrity: sha512-3IhqgeuomNYyurgBRB+08+xdS2pjQfYDWVAuJhNW6U4sR0BHRPzPuAhztNXPNpTFk2K75revFB3/uPJ/aZblcw==} peerDependencies: react: '>=17' @@ -2923,18 +2925,18 @@ packages: d3-zoom: 3.0.0 react: 18.2.0 react-dom: 18.2.0_react@18.2.0 - zustand: 4.3.2_react@18.2.0 + zustand: 4.3.2_immer@9.0.19+react@18.2.0 transitivePeerDependencies: - immer dev: false - /@reactflow/minimap/11.3.3_biqbaboplfbrettd7655fr4n2y: + /@reactflow/minimap/11.3.3_ytuas6axp6gvse4ghxb2libdjm: resolution: {integrity: sha512-EHyiWglFO/CMSERmkVRKtC2kKHWBYrOg2naXP5WD2rh24gm73B8Al1PJ7INuiaQHAEbS1iOw/uKi0up4spu8Ww==} peerDependencies: react: '>=17' react-dom: '>=17' dependencies: - '@reactflow/core': 11.5.0_biqbaboplfbrettd7655fr4n2y + '@reactflow/core': 11.5.0_ytuas6axp6gvse4ghxb2libdjm '@types/d3-selection': 3.0.3 '@types/d3-zoom': 3.0.1 classcat: 5.0.4 @@ -2942,22 +2944,22 @@ packages: d3-zoom: 3.0.0 react: 18.2.0 react-dom: 18.2.0_react@18.2.0 - zustand: 4.3.2_react@18.2.0 + zustand: 4.3.2_immer@9.0.19+react@18.2.0 transitivePeerDependencies: - immer dev: false - /@reactflow/node-toolbar/1.1.3_biqbaboplfbrettd7655fr4n2y: + /@reactflow/node-toolbar/1.1.3_ytuas6axp6gvse4ghxb2libdjm: resolution: {integrity: sha512-D45OGjyo9F8kjKe66RS/qIsipEezlVn1dWGLsYZBkL3K/1zw/aSK/StJHdHLhonWRnDwPZyrcfCu9wbpZxDZlQ==} peerDependencies: react: '>=17' react-dom: '>=17' dependencies: - '@reactflow/core': 11.5.0_biqbaboplfbrettd7655fr4n2y + '@reactflow/core': 11.5.0_ytuas6axp6gvse4ghxb2libdjm classcat: 5.0.4 react: 18.2.0 react-dom: 18.2.0_react@18.2.0 - zustand: 4.3.2_react@18.2.0 + zustand: 4.3.2_immer@9.0.19+react@18.2.0 transitivePeerDependencies: - immer dev: false @@ -9671,6 +9673,10 @@ packages: queue: 6.0.1 dev: true + /immer/9.0.19: + resolution: {integrity: sha512-eY+Y0qcsB4TZKwgQzLaE/lqYMlKhv5J9dyd2RhhtGhNo2njPXDqU9XPfcNfa3MIDsdtZt5KlkIsirlo4dHsWdQ==} + dev: false + /immutable/4.1.0: resolution: {integrity: sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==} dev: true @@ -14070,17 +14076,17 @@ packages: react: 18.2.0 dev: false - /reactflow/11.5.1_biqbaboplfbrettd7655fr4n2y: + /reactflow/11.5.1_ytuas6axp6gvse4ghxb2libdjm: resolution: {integrity: sha512-njujIQ5zoCREB5WCKWDZLQJOU6e4eY6M3eOvyMboqFUIbiUQwqzQ5FtM8njTCUZA1cYBGQLE2zGwdxa3RhYVbw==} peerDependencies: react: '>=17' react-dom: '>=17' dependencies: - '@reactflow/background': 11.1.3_biqbaboplfbrettd7655fr4n2y - '@reactflow/controls': 11.1.3_biqbaboplfbrettd7655fr4n2y - '@reactflow/core': 11.5.0_biqbaboplfbrettd7655fr4n2y - '@reactflow/minimap': 11.3.3_biqbaboplfbrettd7655fr4n2y - '@reactflow/node-toolbar': 1.1.3_biqbaboplfbrettd7655fr4n2y + '@reactflow/background': 11.1.3_ytuas6axp6gvse4ghxb2libdjm + '@reactflow/controls': 11.1.3_ytuas6axp6gvse4ghxb2libdjm + '@reactflow/core': 11.5.0_ytuas6axp6gvse4ghxb2libdjm + '@reactflow/minimap': 11.3.3_ytuas6axp6gvse4ghxb2libdjm + '@reactflow/node-toolbar': 1.1.3_ytuas6axp6gvse4ghxb2libdjm react: 18.2.0 react-dom: 18.2.0_react@18.2.0 transitivePeerDependencies: @@ -16462,7 +16468,7 @@ packages: commander: 2.20.3 dev: true - /zustand/4.3.2_react@18.2.0: + /zustand/4.3.2_immer@9.0.19+react@18.2.0: resolution: {integrity: sha512-rd4haDmlwMTVWVqwvgy00ny8rtti/klRoZjFbL/MAcDnmD5qSw/RZc+Vddstdv90M5Lv6RPgWvm1Hivyn0QgJw==} engines: {node: '>=12.7.0'} peerDependencies: @@ -16474,6 +16480,7 @@ packages: react: optional: true dependencies: + immer: 9.0.19 react: 18.2.0 use-sync-external-store: 1.2.0_react@18.2.0 dev: false From 34f78f6dd5553da204013320b6cc3e53dfd55f51 Mon Sep 17 00:00:00 2001 From: liulei Date: Wed, 1 Feb 2023 23:27:51 +0800 Subject: [PATCH 60/68] =?UTF-8?q?feat:=20=E5=88=9D=E5=A7=8B=E5=8C=96?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E6=B5=81=E9=9D=A2=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + packages/core/src/app-factory/index.ts | 51 ++++++-- .../core/src/contexts/AppFactoryContext.ts | 43 +++++- packages/core/src/flow-node/types.ts | 4 + packages/core/src/index.ts | 2 +- .../flow-designer/src/FlowDesigner/index.tsx | 123 ++++++++++++------ .../flow-nodes/src/BranchNode/interpreter.ts | 3 +- .../flow-nodes/src/LooptNode/interpreter.ts | 17 +++ .../src/RunScriptNode/interpreter.ts | 3 +- .../flow-nodes/src/StartNode/interpreter.ts | 9 ++ packages/flow-nodes/src/_/types/index.ts | 4 - packages/flow-nodes/src/index.ts | 4 + .../state-manager/src/WidgetState/index.ts | 8 +- pnpm-lock.yaml | 4 + websites/workspace/package.json | 1 + .../features/page/components/FlowCanvas.tsx | 18 +++ .../src/features/page/components/index.ts | 1 + .../src/features/page/routers/Page.tsx | 28 ++-- widgets/antd/src/TableWidget/index.tsx | 2 +- 19 files changed, 250 insertions(+), 76 deletions(-) create mode 100644 packages/flow-nodes/src/LooptNode/interpreter.ts create mode 100644 packages/flow-nodes/src/StartNode/interpreter.ts create mode 100644 websites/workspace/src/features/page/components/FlowCanvas.tsx create mode 100644 websites/workspace/src/features/page/components/index.ts diff --git a/package.json b/package.json index 5cb079a..f5417ee 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "@modou/core": "workspace:^1.0.0", "@modou/css-in-js": "workspace:^1.0.0", "@modou/evaluate": "workspace:^1.0.0", + "@modou/flow-nodes": "workspace:^0.0.1", "@modou/meta-vfs": "workspace:^0.0.1", "@modou/reactivity": "workspace:^0.0.1", "@modou/reactivity-react": "workspace:^0.0.1", diff --git a/packages/core/src/app-factory/index.ts b/packages/core/src/app-factory/index.ts index f86a34f..e90fc79 100644 --- a/packages/core/src/app-factory/index.ts +++ b/packages/core/src/app-factory/index.ts @@ -4,6 +4,7 @@ import { FC } from 'react' import { mrToJsonSchema, schemeToDefs } from '@modou/refine' import { BaseSetterProps } from '@modou/setters/src/types' +import { FlowNodeInterpreter, FlowNodeMetadata } from '../flow-node' import { WidgetGroupEnum } from '../types' import { WidgetMetadata } from '../widget' @@ -22,15 +23,23 @@ type WidgetRegistry = Record< type SetterElement = FC> +interface FlowNode { + component: FC + metadata: FlowNodeMetadata + interpreter: FlowNodeInterpreter +} + +type FlowNodeRegistry = Record + +interface AppFactoryParams { + // TODO 增加 package 信息 增加umd引入 + widgets: Widget[] + flowNodes: FlowNode[] + setters: Record +} + export class AppFactory { - constructor({ - widgets, - setters, - }: { - // TODO 增加 package 信息 增加umd引入 - widgets: Widget[] - setters: Record - }) { + constructor({ widgets, setters, flowNodes }: AppFactoryParams) { this._widgetRegistry = unionWith( widgets, ({ metadata: preMetadata }, { metadata: curMetadata }) => @@ -42,10 +51,19 @@ export class AppFactory { } return pre }, {}) + this._flowNodeRegistry = unionWith( + flowNodes, + ({ metadata: preMetadata }, { metadata: curMetadata }) => + isEqual(preMetadata.type, curMetadata.type), + ).reduce((pre, cur) => { + pre[cur.metadata.type] = cur + return pre + }, {}) this._setterRegistry = setters } private readonly _widgetRegistry: WidgetRegistry + private readonly _flowNodeRegistry: FlowNodeRegistry private readonly _setterRegistry: Record>> get widgetByType(): WidgetRegistry { @@ -59,6 +77,17 @@ export class AppFactory { }) } + get flowNodeByType(): FlowNodeRegistry { + return new Proxy(this._flowNodeRegistry, { + get(target: FlowNodeRegistry, p: string | symbol, receiver: any): any { + if (Reflect.has(target, p)) { + return Reflect.get(target, p) + } + return new Error(`流节点【${p.toString()}】未注册`) + }, + }) + } + get setterByType() { return new Proxy(this._setterRegistry, { get( @@ -74,11 +103,7 @@ export class AppFactory { }) } - static create(params: { - // TODO 增加 package 信息 增加umd引入 - widgets: Widget[] - setters: Record - }) { + static create(params: AppFactoryParams) { return new AppFactory(params) } } diff --git a/packages/core/src/contexts/AppFactoryContext.ts b/packages/core/src/contexts/AppFactoryContext.ts index 2f964a1..cdfe9bf 100644 --- a/packages/core/src/contexts/AppFactoryContext.ts +++ b/packages/core/src/contexts/AppFactoryContext.ts @@ -1,6 +1,20 @@ -import { createContext, memo } from 'react' +import { createContext, memo, useContext } from 'react' import { AssetVFS } from '@modou/asset-vfs' +import { + BranchNode, + LoopNode, + RunScriptNode, + StartNode, + branchNodeInterpreter, + branchNodeNodeMetadata, + loopNodeInterpreter, + loopNodeMetadata, + runScriptNodeInterpreter, + runScriptNodeMetadata, + startNodeInterpreter, + startNodeMetadata, +} from '@modou/flow-nodes' import { ArraySetter, BooleanSetter, @@ -63,6 +77,28 @@ export const defaultAppFactory = AppFactory.create({ ...widget, component: memo(widget.component), })), + flowNodes: [ + { + component: StartNode, + metadata: startNodeMetadata, + interpreter: startNodeInterpreter, + }, + { + component: BranchNode, + metadata: branchNodeNodeMetadata, + interpreter: branchNodeInterpreter, + }, + { + component: LoopNode, + metadata: loopNodeMetadata, + interpreter: loopNodeInterpreter, + }, + { + component: RunScriptNode, + metadata: runScriptNodeMetadata, + interpreter: runScriptNodeInterpreter, + }, + ], setters: { [SetterTypeEnum.Select]: SelectSetter, [SetterTypeEnum.String]: StringSetter, @@ -73,3 +109,8 @@ export const defaultAppFactory = AppFactory.create({ }) const assetVFS = new AssetVFS({ appFactory: defaultAppFactory }) export const AppFactoryContext = createContext(assetVFS.appFactory) + +export const useAppFactory = () => { + const appFactory = useContext(AppFactoryContext) + return { appFactory } +} diff --git a/packages/core/src/flow-node/types.ts b/packages/core/src/flow-node/types.ts index ad1f3d9..de3589d 100644 --- a/packages/core/src/flow-node/types.ts +++ b/packages/core/src/flow-node/types.ts @@ -9,3 +9,7 @@ export enum FlowNodePortNameEnum { SOURCE = 'SOURCE', TARGET = 'TARGET', } + +export type FlowNodeInterpreter

= ( + props: P, +) => void diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 4343928..196df04 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -1,6 +1,6 @@ export * from './widget' +export * from './flow-node' export * from './app-factory' export * from './types' export * from './contexts' export * from './utils' -export * from './flow-node' diff --git a/packages/flow-designer/src/FlowDesigner/index.tsx b/packages/flow-designer/src/FlowDesigner/index.tsx index 53e35e0..85d0ccb 100644 --- a/packages/flow-designer/src/FlowDesigner/index.tsx +++ b/packages/flow-designer/src/FlowDesigner/index.tsx @@ -1,5 +1,5 @@ -import { useMemoizedFn } from 'ahooks' -import { ComponentProps, FC } from 'react' +import { useClickAway, useMemoizedFn } from 'ahooks' +import { ComponentProps, FC, useRef, useState } from 'react' import ReactFlow, { Controls, Edge, @@ -10,6 +10,7 @@ import ReactFlow, { } from 'reactflow' import 'reactflow/dist/base.css' +import { useAppFactory } from '@modou/core' import { mcss } from '@modou/css-in-js' import { FunctionIcon, TurboEdge, TurboNode } from './components' @@ -95,6 +96,7 @@ const defaultEdgeOptions = { markerEnd: 'edge-circle', } export const FlowDesigner: FC = (props) => { + const { appFactory } = useAppFactory() const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes) const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges) @@ -102,42 +104,78 @@ export const FlowDesigner: FC = (props) => { Required>['onConnect'] >((params) => setEdges((els) => addEdge(params, els))) + const contextMenuRef = useRef(null) + const [contextMenuOpen, setContextMenuOpen] = useState(false) + const [contextMenuPosition, setContextMenuPosition] = useState({ x: 0, y: 0 }) + + useClickAway(() => { + setContextMenuOpen(false) + }, contextMenuRef) + return ( - - - - - - - - - - - - - - - + <> + {contextMenuOpen && ( +

+ 123 +
+ )} + { + setContextMenuPosition({ + x: e.clientX, + y: e.clientY, + }) + setContextMenuOpen(true) + e.preventDefault() + }} + > + + + + + + + + + + + + + + + ) } @@ -316,6 +354,15 @@ export const classes = { .react-flow__attribution a { color: #95679e; } - + `, + contextMenuWrapper: mcss` + position: fixed; + width: 100px; + height: 200px; + left: 0; + top: 0; + z-index: 999999; + color: white; + border: 1px solid red; `, } diff --git a/packages/flow-nodes/src/BranchNode/interpreter.ts b/packages/flow-nodes/src/BranchNode/interpreter.ts index b189a7e..236d053 100644 --- a/packages/flow-nodes/src/BranchNode/interpreter.ts +++ b/packages/flow-nodes/src/BranchNode/interpreter.ts @@ -1,9 +1,8 @@ +import { FlowNodeInterpreter } from '@modou/core' import { evalScript } from '@modou/evaluate' import { MRSchemeBranchNodeProps } from '@modou/flow-nodes' import { mr } from '@modou/refine' -import { FlowNodeInterpreter } from '../_/types' - export const branchNodeInterpreter: FlowNodeInterpreter< mr.infer > = (props) => { diff --git a/packages/flow-nodes/src/LooptNode/interpreter.ts b/packages/flow-nodes/src/LooptNode/interpreter.ts new file mode 100644 index 0000000..c2d8a6d --- /dev/null +++ b/packages/flow-nodes/src/LooptNode/interpreter.ts @@ -0,0 +1,17 @@ +import { FlowNodeInterpreter } from '@modou/core' +import { evalScript } from '@modou/evaluate' +import { MRSchemeLoopNodeProps } from '@modou/flow-nodes' +import { mr } from '@modou/refine' + +export const loopNodeInterpreter: FlowNodeInterpreter< + mr.infer +> = async (props) => { + const iterable = props.props.iterable + const res = await Promise.all( + evalScript(`return ${iterable}`, {}).map((item: any) => { + console.log('item', item) + return 'TODO' + }), + ) + return res +} diff --git a/packages/flow-nodes/src/RunScriptNode/interpreter.ts b/packages/flow-nodes/src/RunScriptNode/interpreter.ts index d36530e..9b2ed7d 100644 --- a/packages/flow-nodes/src/RunScriptNode/interpreter.ts +++ b/packages/flow-nodes/src/RunScriptNode/interpreter.ts @@ -1,9 +1,8 @@ +import { FlowNodeInterpreter } from '@modou/core' import { evalScript } from '@modou/evaluate' import { MRSchemeRunScriptNodeProps } from '@modou/flow-nodes' import { mr } from '@modou/refine' -import { FlowNodeInterpreter } from '../_/types' - export const runScriptNodeInterpreter: FlowNodeInterpreter< mr.infer > = (props) => { diff --git a/packages/flow-nodes/src/StartNode/interpreter.ts b/packages/flow-nodes/src/StartNode/interpreter.ts new file mode 100644 index 0000000..c2f7c12 --- /dev/null +++ b/packages/flow-nodes/src/StartNode/interpreter.ts @@ -0,0 +1,9 @@ +import { FlowNodeInterpreter } from '@modou/core' +import { MRSchemeStartNodeProps } from '@modou/flow-nodes' +import { mr } from '@modou/refine' + +export const startNodeInterpreter: FlowNodeInterpreter< + mr.infer +> = (props) => { + // 直接执行下一步流程 +} diff --git a/packages/flow-nodes/src/_/types/index.ts b/packages/flow-nodes/src/_/types/index.ts index 002dd5f..c5b6d6d 100644 --- a/packages/flow-nodes/src/_/types/index.ts +++ b/packages/flow-nodes/src/_/types/index.ts @@ -33,7 +33,3 @@ export type FlowNodeProps = export type OnChangeNode = ( node: Partial> & { id: string }, ) => void - -export type FlowNodeInterpreter

= ( - props: P, -) => void diff --git a/packages/flow-nodes/src/index.ts b/packages/flow-nodes/src/index.ts index 0a6e4be..b57dc3f 100644 --- a/packages/flow-nodes/src/index.ts +++ b/packages/flow-nodes/src/index.ts @@ -1,11 +1,15 @@ export * from './StartNode' export * from './StartNode/metadata' +export * from './StartNode/interpreter' export * from './RunScriptNode' export * from './RunScriptNode/metadata' +export * from './RunScriptNode/interpreter' export * from './LooptNode' export * from './LooptNode/metadata' +export * from './LooptNode/interpreter' export * from './BranchNode' export * from './BranchNode/metadata' +export * from './BranchNode/interpreter' diff --git a/packages/state-manager/src/WidgetState/index.ts b/packages/state-manager/src/WidgetState/index.ts index 3ffa81f..4414df4 100644 --- a/packages/state-manager/src/WidgetState/index.ts +++ b/packages/state-manager/src/WidgetState/index.ts @@ -169,11 +169,11 @@ export class WidgetState { { fireImmediately: true }, ) this.disposer = () => { - stopReactionVI() - stopReaction() - stopExps.forEach((stop) => stop()) - // stopExps = [] runInAction(() => { + stopReactionVI() + stopReaction() + stopExps.forEach((stop) => stop()) + // stopExps = [] // TODO 处理 v_i 和 v_ri remove(canvasState.subState.widget, this.file.meta.id) }) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b5dcf63..0c914e6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,6 +18,7 @@ importers: '@modou/core': workspace:^1.0.0 '@modou/css-in-js': workspace:^1.0.0 '@modou/evaluate': workspace:^1.0.0 + '@modou/flow-nodes': workspace:^0.0.1 '@modou/meta-vfs': workspace:^0.0.1 '@modou/reactivity': workspace:^0.0.1 '@modou/reactivity-react': workspace:^0.0.1 @@ -81,6 +82,7 @@ importers: '@modou/core': link:packages/core '@modou/css-in-js': link:packages/css-in-js '@modou/evaluate': link:packages/evaluate + '@modou/flow-nodes': link:packages/flow-nodes '@modou/meta-vfs': link:packages/meta-vfs '@modou/reactivity': link:packages/reactivity '@modou/reactivity-react': link:packages/reactivity-react @@ -432,10 +434,12 @@ importers: specifiers: '@ahooksjs/use-url-state': ^3.5.0 '@modou/canvas-designer': workspace:^1.0.0 + '@modou/flow-designer': workspace:^0.0.1 mitt: ^3.0.0 dependencies: '@ahooksjs/use-url-state': 3.5.0 '@modou/canvas-designer': link:../../packages/canvas-designer + '@modou/flow-designer': link:../../packages/flow-designer mitt: 3.0.0 widgets/antd: diff --git a/websites/workspace/package.json b/websites/workspace/package.json index ffb2607..c8052c1 100644 --- a/websites/workspace/package.json +++ b/websites/workspace/package.json @@ -12,6 +12,7 @@ "dependencies": { "@ahooksjs/use-url-state": "^3.5.0", "@modou/canvas-designer": "workspace:^1.0.0", + "@modou/flow-designer": "workspace:^0.0.1", "mitt": "^3.0.0" } } diff --git a/websites/workspace/src/features/page/components/FlowCanvas.tsx b/websites/workspace/src/features/page/components/FlowCanvas.tsx new file mode 100644 index 0000000..037b564 --- /dev/null +++ b/websites/workspace/src/features/page/components/FlowCanvas.tsx @@ -0,0 +1,18 @@ +import { FC } from 'react' + +import { mcss } from '@modou/css-in-js' +import { FlowDesigner } from '@modou/flow-designer' + +export const FlowCanvas: FC = () => { + return ( +

+ +
+ ) +} + +const classes = { + wrapper: mcss` + height: 100%; + `, +} diff --git a/websites/workspace/src/features/page/components/index.ts b/websites/workspace/src/features/page/components/index.ts new file mode 100644 index 0000000..3981c8c --- /dev/null +++ b/websites/workspace/src/features/page/components/index.ts @@ -0,0 +1 @@ +export { FlowCanvas } from './FlowCanvas' diff --git a/websites/workspace/src/features/page/routers/Page.tsx b/websites/workspace/src/features/page/routers/Page.tsx index 8e6a941..3b1a4ae 100644 --- a/websites/workspace/src/features/page/routers/Page.tsx +++ b/websites/workspace/src/features/page/routers/Page.tsx @@ -3,7 +3,7 @@ import { PageRouterParamsKey } from '@/types' import { generateRouterPath } from '@/utils/router' import { Col, Row } from 'antd' import { head } from 'lodash' -import { FC, useEffect, useLayoutEffect } from 'react' +import { FC, useLayoutEffect } from 'react' import { useNavigate, useParams } from 'react-router-dom' import { CanvasDesigner } from '@modou/canvas-designer' @@ -16,6 +16,8 @@ import { mcss } from '@modou/css-in-js' import { observer } from '@modou/reactivity-react' import { SimulatorPC } from '@modou/simulator' +import { FlowCanvas } from '../components' + const _Page: FC = () => { const { pageId, appId } = useParams() const { appManager } = useAppManager() @@ -37,17 +39,20 @@ const _Page: FC = () => { }, [appId, appManager.app.pages, navigate, page]) return ( - - - {page && ( - + + + + {page && ( - - )} - - + )} + + + + + + ) } export const Page = observer(_Page) @@ -57,6 +62,9 @@ const classes = { height: 100%; `, container: mcss` - height: 100%; + height: 50%; + `, + flowWrapper: mcss` + height: 50%; `, } diff --git a/widgets/antd/src/TableWidget/index.tsx b/widgets/antd/src/TableWidget/index.tsx index 1ae6c56..6f99e05 100644 --- a/widgets/antd/src/TableWidget/index.tsx +++ b/widgets/antd/src/TableWidget/index.tsx @@ -71,7 +71,7 @@ export const TableWidget: FC< dataSource={isArray(dataSource) ? dataSource : []} search={false} options={false} - rowKey={(record) => record.id || Math.random()} + rowKey={(record, index) => record.id || index} cardProps={{ bodyStyle: { padding: 0, From 0b86a3642ebf9b860c1337e73a334be6cca709fd Mon Sep 17 00:00:00 2001 From: liulei Date: Thu, 2 Feb 2023 10:00:36 +0800 Subject: [PATCH 61/68] =?UTF-8?q?feat(workspace):=20=E5=88=9D=E6=AD=A5?= =?UTF-8?q?=E9=9B=86=E6=88=90flow-designer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../flow-nodes/src/BranchNode/metadata.tsx | 1 - .../src/{LooptNode => LoopNode}/demo.tsx | 0 .../src/{LooptNode => LoopNode}/index.md | 0 .../src/{LooptNode => LoopNode}/index.tsx | 0 .../{LooptNode => LoopNode}/interpreter.ts | 0 .../src/{LooptNode => LoopNode}/metadata.tsx | 0 packages/flow-nodes/src/index.ts | 6 +- packages/meta-vfs/src/FlowEdgeFile/index.ts | 61 ++++++++++++ packages/meta-vfs/src/FlowFile/index.ts | 94 +++++++++++++++++++ packages/meta-vfs/src/FlowNodeFile/index.ts | 61 ++++++++++++ packages/meta-vfs/src/PageFile/index.ts | 14 +++ .../features/page/components/FlowCanvas.tsx | 1 + .../src/features/page/components/FlowList.tsx | 15 +++ .../src/features/page/routers/Page.tsx | 3 + 14 files changed, 252 insertions(+), 4 deletions(-) rename packages/flow-nodes/src/{LooptNode => LoopNode}/demo.tsx (100%) rename packages/flow-nodes/src/{LooptNode => LoopNode}/index.md (100%) rename packages/flow-nodes/src/{LooptNode => LoopNode}/index.tsx (100%) rename packages/flow-nodes/src/{LooptNode => LoopNode}/interpreter.ts (100%) rename packages/flow-nodes/src/{LooptNode => LoopNode}/metadata.tsx (100%) create mode 100644 packages/meta-vfs/src/FlowEdgeFile/index.ts create mode 100644 packages/meta-vfs/src/FlowFile/index.ts create mode 100644 packages/meta-vfs/src/FlowNodeFile/index.ts create mode 100644 websites/workspace/src/features/page/components/FlowList.tsx diff --git a/packages/flow-nodes/src/BranchNode/metadata.tsx b/packages/flow-nodes/src/BranchNode/metadata.tsx index 98e059c..eeeb7ba 100644 --- a/packages/flow-nodes/src/BranchNode/metadata.tsx +++ b/packages/flow-nodes/src/BranchNode/metadata.tsx @@ -1,7 +1,6 @@ import { AndroidOutlined } from '@ant-design/icons' import { FlowNodeMetadata, FlowNodePortNameEnum } from '@modou/core' -// eslint-disable-next-line @typescript-eslint/no-unused-vars import { mr } from '@modou/refine' import { FlowNodeEnum } from '../_/types' diff --git a/packages/flow-nodes/src/LooptNode/demo.tsx b/packages/flow-nodes/src/LoopNode/demo.tsx similarity index 100% rename from packages/flow-nodes/src/LooptNode/demo.tsx rename to packages/flow-nodes/src/LoopNode/demo.tsx diff --git a/packages/flow-nodes/src/LooptNode/index.md b/packages/flow-nodes/src/LoopNode/index.md similarity index 100% rename from packages/flow-nodes/src/LooptNode/index.md rename to packages/flow-nodes/src/LoopNode/index.md diff --git a/packages/flow-nodes/src/LooptNode/index.tsx b/packages/flow-nodes/src/LoopNode/index.tsx similarity index 100% rename from packages/flow-nodes/src/LooptNode/index.tsx rename to packages/flow-nodes/src/LoopNode/index.tsx diff --git a/packages/flow-nodes/src/LooptNode/interpreter.ts b/packages/flow-nodes/src/LoopNode/interpreter.ts similarity index 100% rename from packages/flow-nodes/src/LooptNode/interpreter.ts rename to packages/flow-nodes/src/LoopNode/interpreter.ts diff --git a/packages/flow-nodes/src/LooptNode/metadata.tsx b/packages/flow-nodes/src/LoopNode/metadata.tsx similarity index 100% rename from packages/flow-nodes/src/LooptNode/metadata.tsx rename to packages/flow-nodes/src/LoopNode/metadata.tsx diff --git a/packages/flow-nodes/src/index.ts b/packages/flow-nodes/src/index.ts index b57dc3f..44ea5d7 100644 --- a/packages/flow-nodes/src/index.ts +++ b/packages/flow-nodes/src/index.ts @@ -6,9 +6,9 @@ export * from './RunScriptNode' export * from './RunScriptNode/metadata' export * from './RunScriptNode/interpreter' -export * from './LooptNode' -export * from './LooptNode/metadata' -export * from './LooptNode/interpreter' +export * from './LoopNode' +export * from './LoopNode/metadata' +export * from './LoopNode/interpreter' export * from './BranchNode' export * from './BranchNode/metadata' diff --git a/packages/meta-vfs/src/FlowEdgeFile/index.ts b/packages/meta-vfs/src/FlowEdgeFile/index.ts new file mode 100644 index 0000000..8b17f91 --- /dev/null +++ b/packages/meta-vfs/src/FlowEdgeFile/index.ts @@ -0,0 +1,61 @@ +import { omit } from 'lodash' + +import { FileTypeEnum } from '@modou/meta-vfs' +import { makeObservable, observable, runInAction } from '@modou/reactivity' + +import { BaseFile, BaseFileMete } from '../BaseFile' +import { FlowFile } from '../FlowFile' + +export type FlowEdgeFileMeta = BaseFileMete<{ + id: string + source: string + target: string + sourceHandle: string + targetHandle: string +}> +export class FlowEdgeFile extends BaseFile<{}, FlowEdgeFileMeta, FlowFile> { + constructor(meta: FlowEdgeFileMeta, parentFile: FlowFile) { + super({ + fileType: FileTypeEnum.FlowEdge, + meta, + parentFile, + }) + makeObservable(this, { + subFileMap: observable, + }) + } + + subFileMap = {} + toJSON() { + return { + ...this.meta, + ...this.subFileMapToJson(), + fileType: this.fileType, + } + } + + static create(meta: Omit, parentFile: FlowFile) { + return runInAction(() => { + const flowEdgeFile = new FlowEdgeFile( + { + ...meta, + version: '0.0.1', + // FIXME ts type + } as unknown as FlowEdgeFileMeta, + parentFile, + ) + parentFile.flowEdges.push(flowEdgeFile) + return flowEdgeFile + }) + } + + static formJSON( + json: ReturnType, + parentFile: FlowFile, + ): FlowEdgeFile { + return FlowEdgeFile.create( + omit(json, 'fileType') as FlowEdgeFileMeta, + parentFile, + ) + } +} diff --git a/packages/meta-vfs/src/FlowFile/index.ts b/packages/meta-vfs/src/FlowFile/index.ts new file mode 100644 index 0000000..46fc523 --- /dev/null +++ b/packages/meta-vfs/src/FlowFile/index.ts @@ -0,0 +1,94 @@ +import { omit } from 'lodash' + +import { FileTypeEnum, PageFile } from '@modou/meta-vfs' +import { + computed, + makeObservable, + observable, + runInAction, +} from '@modou/reactivity' + +import { BaseFile, BaseFileMap, BaseFileMete } from '../BaseFile' +import { FlowEdgeFile } from '../FlowEdgeFile' +import { FlowNodeFile } from '../FlowNodeFile' + +export type FlowFileMeta = BaseFileMete<{ + readonly name: string +}> + +interface FileMap extends BaseFileMap { + readonly flowNodes: FlowNodeFile[] + readonly flowEdges: FlowEdgeFile[] +} + +export class FlowFile extends BaseFile { + protected constructor(meta: FlowFileMeta, parentFile: PageFile) { + super({ fileType: FileTypeEnum.Flow, meta, parentFile }) + makeObservable(this, { + subFileMap: observable, + flowNodes: computed, + flowEdges: computed, + }) + } + + subFileMap: FileMap = { + flowNodes: [], + flowEdges: [], + } + + get flowNodes() { + return this.subFileMap.flowNodes + } + + get flowEdges() { + return this.subFileMap.flowEdges + } + + toJSON() { + return { + ...this.meta, + ...this.subFileMapToJson(), + fileType: this.fileType, + } + } + + // TODO 所有 version 提到 create 函数内部 + static create(meta: FlowFileMeta, parentFile: PageFile) { + return runInAction(() => { + const flowFile = new FlowFile( + { + ...meta, + version: '0.0.1', + }, + parentFile, + ) + parentFile.flows.push(flowFile) + return flowFile + }) + } + + static formJSON( + json: ReturnType, + parentFile: PageFile, + ): FlowFile { + return runInAction(() => { + const flowFile = FlowFile.create( + omit(json, ['fileType', 'flowNodes']), + parentFile, + ) + json.flowNodes.map((flowNode) => + FlowNodeFile.formJSON( + flowNode as unknown as ReturnType, + flowFile, + ), + ) + json.flowEdges.map((flowEdge) => + FlowEdgeFile.formJSON( + flowEdge as unknown as ReturnType, + flowFile, + ), + ) + return flowFile + }) + } +} diff --git a/packages/meta-vfs/src/FlowNodeFile/index.ts b/packages/meta-vfs/src/FlowNodeFile/index.ts new file mode 100644 index 0000000..0f1cbb1 --- /dev/null +++ b/packages/meta-vfs/src/FlowNodeFile/index.ts @@ -0,0 +1,61 @@ +import { omit } from 'lodash' + +import { FlowNodeBaseProps } from '@modou/core' +import { FileTypeEnum } from '@modou/meta-vfs' +import { makeObservable, observable, runInAction } from '@modou/reactivity' + +import { BaseFile, BaseFileMete } from '../BaseFile' +import { FlowFile } from '../FlowFile' + +export type FlowNodeFileMeta = + BaseFileMete + +export class FlowNodeFile extends BaseFile<{}, FlowNodeFileMeta, FlowFile> { + constructor(meta: FlowNodeFileMeta, parentFile: FlowFile) { + super({ + fileType: FileTypeEnum.FlowNode, + meta, + parentFile, + }) + makeObservable(this, { + subFileMap: observable, + }) + } + + subFileMap = {} + toJSON() { + return { + ...this.meta, + ...this.subFileMapToJson(), + fileType: this.fileType, + } + } + + static create( + meta: Omit, + parentFile: FlowFile, + ) { + return runInAction(() => { + const entityFieldFile = new FlowNodeFile( + { + ...meta, + version: '0.0.1', + // FIXME ts type + } as unknown as FlowNodeFileMeta, + parentFile, + ) + parentFile.flowNodes.push(entityFieldFile) + return entityFieldFile + }) + } + + static formJSON( + json: ReturnType, + parentFile: FlowFile, + ): FlowNodeFile { + return FlowNodeFile.create( + omit(json, 'fileType') as FlowNodeFileMeta, + parentFile, + ) + } +} diff --git a/packages/meta-vfs/src/PageFile/index.ts b/packages/meta-vfs/src/PageFile/index.ts index 279f48d..359ca21 100644 --- a/packages/meta-vfs/src/PageFile/index.ts +++ b/packages/meta-vfs/src/PageFile/index.ts @@ -12,6 +12,7 @@ import { MDTernDefs } from '@modou/refine' import { AppFile } from '../AppFile' import { BaseFile, BaseFileMap, BaseFileMete } from '../BaseFile' +import { FlowFile } from '../FlowFile' import { WidgetFile, WidgetFileMeta } from '../WidgetFile' import { FileTypeEnum, UpdateParams } from '../types' @@ -30,6 +31,7 @@ type WidgetRelationById = Record interface FileMap extends BaseFileMap { readonly widgets: WidgetFile[] + readonly flows: FlowFile[] } export class PageFile extends BaseFile { @@ -44,17 +46,23 @@ export class PageFile extends BaseFile { deleteWidget: action, updateWidgets: action, moveWidget: action, + flows: computed, }) } subFileMap: FileMap = { widgets: [], + flows: [], } get widgets() { return this.subFileMap.widgets } + get flows() { + return this.subFileMap.flows + } + get widgetMap() { return keyBy(this.subFileMap.widgets, (widget) => widget.meta.id) } @@ -282,6 +290,12 @@ export class PageFile extends BaseFile { pageFile, ), ) + json.flows.map((flow) => + FlowFile.formJSON( + flow as unknown as ReturnType, + pageFile, + ), + ) return pageFile }) } diff --git a/websites/workspace/src/features/page/components/FlowCanvas.tsx b/websites/workspace/src/features/page/components/FlowCanvas.tsx index 037b564..803d24e 100644 --- a/websites/workspace/src/features/page/components/FlowCanvas.tsx +++ b/websites/workspace/src/features/page/components/FlowCanvas.tsx @@ -14,5 +14,6 @@ export const FlowCanvas: FC = () => { const classes = { wrapper: mcss` height: 100%; + flex: 1; `, } diff --git a/websites/workspace/src/features/page/components/FlowList.tsx b/websites/workspace/src/features/page/components/FlowList.tsx new file mode 100644 index 0000000..1766ae0 --- /dev/null +++ b/websites/workspace/src/features/page/components/FlowList.tsx @@ -0,0 +1,15 @@ +import { FC } from 'react' + +import { mcss } from '@modou/css-in-js' + +export const FlowList: FC = () => { + return
FlowList
+} + +const classes = { + wrapper: mcss` + width: 220px; + border: 1px solid green; + background-color: white; + `, +} diff --git a/websites/workspace/src/features/page/routers/Page.tsx b/websites/workspace/src/features/page/routers/Page.tsx index 3b1a4ae..1df75d0 100644 --- a/websites/workspace/src/features/page/routers/Page.tsx +++ b/websites/workspace/src/features/page/routers/Page.tsx @@ -17,6 +17,7 @@ import { observer } from '@modou/reactivity-react' import { SimulatorPC } from '@modou/simulator' import { FlowCanvas } from '../components' +import { FlowList } from '../components/FlowList' const _Page: FC = () => { const { pageId, appId } = useParams() @@ -49,6 +50,7 @@ const _Page: FC = () => { )} + @@ -66,5 +68,6 @@ const classes = { `, flowWrapper: mcss` height: 50%; + display: flex; `, } From 3be215ddb879c3c01f765ed63a2416878a354c7c Mon Sep 17 00:00:00 2001 From: liulei Date: Fri, 3 Feb 2023 00:50:42 +0800 Subject: [PATCH 62/68] =?UTF-8?q?refactor(render):=20=E9=87=8D=E6=9E=84can?= =?UTF-8?q?vas-state?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/CanvasDesigner.tsx | 29 ++++-- .../src/components/CanvasDesignerCanvas.tsx | 7 +- .../render/src/components/ReactRender.tsx | 21 +++-- .../render/src/components/WidgetVirtual.tsx | 16 ++-- packages/render/src/constants/index.ts | 2 + packages/render/src/hooks/index.ts | 1 - packages/render/src/hooks/useInitRender.ts | 43 ++++++++- .../render/src/hooks/useInitStateManager.ts | 28 ------ packages/render/src/utils/ReactRenderHost.ts | 12 +++ .../state-manager/src/StateManager/index.ts | 21 ----- .../src/contexts/AppStateContext.tsx | 20 ++++ .../src/contexts/CanvasStateContext.tsx | 20 ++++ .../src/contexts/StateManagerContext.tsx | 26 ----- packages/state-manager/src/contexts/index.ts | 3 +- packages/state-manager/src/index.ts | 1 - .../src/features/app/routers/App.tsx | 94 +++++++++++-------- 16 files changed, 195 insertions(+), 149 deletions(-) delete mode 100644 packages/render/src/hooks/useInitStateManager.ts delete mode 100644 packages/state-manager/src/StateManager/index.ts create mode 100644 packages/state-manager/src/contexts/AppStateContext.tsx create mode 100644 packages/state-manager/src/contexts/CanvasStateContext.tsx delete mode 100644 packages/state-manager/src/contexts/StateManagerContext.tsx diff --git a/packages/canvas-designer/src/components/CanvasDesigner.tsx b/packages/canvas-designer/src/components/CanvasDesigner.tsx index 85da889..762ff0c 100644 --- a/packages/canvas-designer/src/components/CanvasDesigner.tsx +++ b/packages/canvas-designer/src/components/CanvasDesigner.tsx @@ -1,8 +1,9 @@ -import { FC, ReactElement, useEffect } from 'react' +import { FC, ReactElement, useEffect, useState } from 'react' import { DndProvider } from 'react-dnd' import { HTML5Backend } from 'react-dnd-html5-backend' import { PageFile } from '@modou/meta-vfs' +import { CanvasStateProvider, PageState } from '@modou/state-manager' import { CanvasDesignerFileProvider } from '../contexts/CanvasDesignerFileContext' import { CanvasDesignerStoreProvider } from '../contexts/CanvasDesignerStoreContext' @@ -14,13 +15,25 @@ interface CanvasDesignerProps { } export const CanvasDesigner: FC = ({ file, children }) => { - return ( + const [canvasState, setCanvasState] = useState() + + useEffect(() => { + // TODO 添加到 AppState + if (canvasState?.file === file) { + return + } + setCanvasState(new PageState(file)) + }, [canvasState?.file, file]) + + return canvasState ? ( - - - {children} - - + + + + {children} + + + - ) + ) : null } diff --git a/packages/canvas-designer/src/components/CanvasDesignerCanvas.tsx b/packages/canvas-designer/src/components/CanvasDesignerCanvas.tsx index 025c3bb..2c8b7fa 100644 --- a/packages/canvas-designer/src/components/CanvasDesignerCanvas.tsx +++ b/packages/canvas-designer/src/components/CanvasDesignerCanvas.tsx @@ -13,6 +13,7 @@ import { import { useAppManager } from '@modou/core' import { mcss } from '@modou/css-in-js' import { observer } from '@modou/reactivity-react' +import { useAppState, useCanvasState } from '@modou/state-manager' import { SimulatorInstanceContext } from '../contexts' import { useCanvasDesignerFile } from '../contexts/CanvasDesignerFileContext' @@ -25,6 +26,8 @@ export const _CanvasDesignerCanvas: FC<{ const iframeRef = useRef(null) const [initializedIframe, setInitializedIframe] = useState(false) const { appManager } = useAppManager() + const { appState } = useAppState() + const { canvasState } = useCanvasState() const { canvasDesignerFile } = useCanvasDesignerFile() useEffect(() => { @@ -37,7 +40,9 @@ export const _CanvasDesignerCanvas: FC<{ iframeRef.current?.contentWindow?.reactRenderHost.updateFile( canvasDesignerFile, ) - }, [initializedIframe, appManager, canvasDesignerFile]) + iframeRef.current?.contentWindow?.reactRenderHost.updateState(canvasState) + iframeRef.current?.contentWindow?.reactRenderHost.updateAppState(appState) + }, [initializedIframe, appManager, canvasDesignerFile, appState, canvasState]) const canvasRef = useRef(null) const [designerIndicatorStyle, setDesignerIndicatorStyle] = useState({ diff --git a/packages/render/src/components/ReactRender.tsx b/packages/render/src/components/ReactRender.tsx index 639a14f..44ee62a 100644 --- a/packages/render/src/components/ReactRender.tsx +++ b/packages/render/src/components/ReactRender.tsx @@ -6,20 +6,19 @@ import * as React from 'react' import { AppFactoryContext, AppManagerProvider } from '@modou/core' import { observer } from '@modou/reactivity-react' -import { StateManagerProvider } from '@modou/state-manager' +import { AppStateProvider, CanvasStateProvider } from '@modou/state-manager' import { CanvasFileContextProvider } from '../contexts' -import { useInitRender, useInitStateManager } from '../hooks' +import { useInitRender } from '../hooks' import { MoDouRenderProps } from '../types' import { ReactRenderTolerant } from './ReactRenderTolerant' // TODO 支持页面的 State 缓存 比如详情页面回退到列表页面 const _ReactRender: FC = (props) => { const appFactory = useContext(AppFactoryContext) - const { file, appManager } = useInitRender() - const { stateManager } = useInitStateManager({ app: appManager?.app, file }) + const { file, appManager, appState, state } = useInitRender() - if (!file || !appManager || !stateManager) { + if (!file || !appManager || !appState || !state) { return null } return ( @@ -27,13 +26,15 @@ const _ReactRender: FC = (props) => { {/* TODO 去除点(.)保持跟其他Context统一 */} - + - - - + + + + + - + diff --git a/packages/render/src/components/WidgetVirtual.tsx b/packages/render/src/components/WidgetVirtual.tsx index 7d3d65a..0664761 100644 --- a/packages/render/src/components/WidgetVirtual.tsx +++ b/packages/render/src/components/WidgetVirtual.tsx @@ -1,13 +1,12 @@ -import { useMount, useUnmount } from 'ahooks' import { FC, useContext, useEffect, useState } from 'react' import * as React from 'react' import { AppFactoryContext, useAppManager } from '@modou/core' -import { runInAction, toJS } from '@modou/reactivity' +import { toJS } from '@modou/reactivity' import { observer, useLocalObservable } from '@modou/reactivity-react' import { WidgetState, - useStateManager, + useCanvasState, useWidgetVariables, } from '@modou/state-manager' @@ -21,7 +20,7 @@ const _WidgetVirtual: FC<{ const { widgetVariables } = useWidgetVariables() const { appManager } = useAppManager() - const { canvasState } = useStateManager() + const { canvasState } = useCanvasState() const widget = appManager.widgetMap[widgetId] const appFactory = useContext(AppFactoryContext) const widgetDef = appFactory.widgetByType[widget.meta.type] @@ -68,17 +67,20 @@ const _WidgetVirtual: FC<{ const [widgetState, setWidgetState] = useState() useEffect(() => { - const widgetState = new WidgetState(widget, { + if (widget === widgetState?.file) { + return + } + const _widgetState = new WidgetState(widget, { appFactory, widgetVariables, canvasState, }) - setWidgetState(widgetState) + setWidgetState(_widgetState) return () => { widgetState?.disposer() } // 不要添加多余deps,保持为空 - }, []) + }, [appFactory, canvasState, widget, widgetState, widgetVariables]) useEffect(() => { widgetState?.updateWidgetVariables(widgetVariables) diff --git a/packages/render/src/constants/index.ts b/packages/render/src/constants/index.ts index d1ecd7a..a171c1a 100644 --- a/packages/render/src/constants/index.ts +++ b/packages/render/src/constants/index.ts @@ -1,2 +1,4 @@ export const APP_MANAGER_SYMBOL = Symbol('AppManager') export const FILE_SYMBOL = Symbol('File') +export const APP_STATE_SYMBOL = Symbol('AppState') +export const STATE_SYMBOL = Symbol('State') diff --git a/packages/render/src/hooks/index.ts b/packages/render/src/hooks/index.ts index 5faee6d..95253b2 100644 --- a/packages/render/src/hooks/index.ts +++ b/packages/render/src/hooks/index.ts @@ -1,2 +1 @@ export { useInitRender } from './useInitRender' -export { useInitStateManager } from './useInitStateManager' diff --git a/packages/render/src/hooks/useInitRender.ts b/packages/render/src/hooks/useInitRender.ts index 3d3093d..1f77294 100644 --- a/packages/render/src/hooks/useInitRender.ts +++ b/packages/render/src/hooks/useInitRender.ts @@ -2,15 +2,28 @@ import { useMemoizedFn } from 'ahooks' import { useEffect, useState } from 'react' import { AppManager, PageFile } from '@modou/meta-vfs' +import { AppState, PageState } from '@modou/state-manager' -import { APP_MANAGER_SYMBOL, FILE_SYMBOL } from '../constants' +import { + APP_MANAGER_SYMBOL, + APP_STATE_SYMBOL, + FILE_SYMBOL, + STATE_SYMBOL, +} from '../constants' import { ReactRenderHost } from '../utils' -import { UpdateAppManager, UpdateFile } from '../utils/ReactRenderHost' +import { + UpdateAppManager, + UpdateAppState, + UpdateFile, + UpdateState, +} from '../utils/ReactRenderHost' export const useInitRender = () => { // TODO 判断 host type 浏览器 or 模拟器 const [appManager, updateAppManager] = useState() const [file, updateFile] = useState() + const [appState, updateAppState] = useState() + const [state, updateState] = useState() const _updateAppManager: UpdateAppManager = useMemoizedFn((appManager) => { if (!Reflect.get(window, APP_MANAGER_SYMBOL)) { Reflect.set(window, APP_MANAGER_SYMBOL, appManager) @@ -23,14 +36,28 @@ export const useInitRender = () => { } updateFile(file) }) + const _updateAppState: UpdateAppState = useMemoizedFn((appState) => { + if (!Reflect.get(window, APP_STATE_SYMBOL)) { + Reflect.set(window, APP_STATE_SYMBOL, appState) + } + updateAppState(appState) + }) + const _updateState: UpdateState = useMemoizedFn((state) => { + if (!Reflect.get(window, STATE_SYMBOL)) { + Reflect.set(window, STATE_SYMBOL, state) + } + updateState(state) + }) useEffect(() => { if (!window.reactRenderHost) { window.reactRenderHost = new ReactRenderHost({ updateAppManager: _updateAppManager, updateFile: _updateFile, + updateState: _updateState, + updateAppState: _updateAppState, }) } - }, [_updateAppManager, _updateFile]) + }, [_updateAppManager, _updateFile, _updateState, _updateAppState]) useEffect(() => { if (Reflect.get(window, APP_MANAGER_SYMBOL)) { @@ -39,10 +66,18 @@ export const useInitRender = () => { if (Reflect.get(window, FILE_SYMBOL)) { updateFile(Reflect.get(window, FILE_SYMBOL)) } - }) + if (Reflect.get(window, APP_STATE_SYMBOL)) { + updateAppState(Reflect.get(window, APP_STATE_SYMBOL)) + } + if (Reflect.get(window, STATE_SYMBOL)) { + updateState(Reflect.get(window, STATE_SYMBOL)) + } + }, []) return { file, appManager, + appState, + state, } } diff --git a/packages/render/src/hooks/useInitStateManager.ts b/packages/render/src/hooks/useInitStateManager.ts deleted file mode 100644 index ef50ea0..0000000 --- a/packages/render/src/hooks/useInitStateManager.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { useEffect, useState } from 'react' - -import { AppFile, PageFile } from '@modou/meta-vfs' -import { AppState, PageState, StateManager } from '@modou/state-manager' - -export const useInitStateManager = ({ - app, - file, -}: { - app?: AppFile - file?: PageFile -}) => { - const [stateManager, setStateManager] = useState() - useEffect(() => { - if (!app || !file) { - return - } - setStateManager( - new StateManager({ - appState: new AppState(app), - canvasState: new PageState(file), - }), - ) - }, [app, file]) - return { - stateManager, - } -} diff --git a/packages/render/src/utils/ReactRenderHost.ts b/packages/render/src/utils/ReactRenderHost.ts index 71f5b90..31b30ef 100644 --- a/packages/render/src/utils/ReactRenderHost.ts +++ b/packages/render/src/utils/ReactRenderHost.ts @@ -1,20 +1,32 @@ import { AppManager, PageFile } from '@modou/meta-vfs' +import { AppState, PageState } from '@modou/state-manager' export type UpdateAppManager = (appManager: AppManager) => void export type UpdateFile = (file: PageFile) => void +export type UpdateAppState = (appState: AppState) => void +export type UpdateState = (file: PageState) => void + export class ReactRenderHost { constructor({ updateAppManager, updateFile, + updateAppState, + updateState, }: { updateAppManager: UpdateAppManager updateFile: UpdateFile + updateAppState: UpdateAppState + updateState: UpdateState }) { this.updateAppManager = updateAppManager this.updateFile = updateFile + this.updateAppState = updateAppState + this.updateState = updateState } updateAppManager updateFile + updateAppState + updateState } diff --git a/packages/state-manager/src/StateManager/index.ts b/packages/state-manager/src/StateManager/index.ts deleted file mode 100644 index e88c91e..0000000 --- a/packages/state-manager/src/StateManager/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { makeAutoObservable } from '@modou/reactivity' - -import { AppState } from '../AppState' -import { PageState } from '../PageState' - -export class StateManager { - constructor({ - appState, - canvasState, - }: { - appState: AppState - canvasState: PageState - }) { - this.app = appState - this.canvas = canvasState - makeAutoObservable(this) - } - - app: AppState - canvas: PageState -} diff --git a/packages/state-manager/src/contexts/AppStateContext.tsx b/packages/state-manager/src/contexts/AppStateContext.tsx new file mode 100644 index 0000000..6151303 --- /dev/null +++ b/packages/state-manager/src/contexts/AppStateContext.tsx @@ -0,0 +1,20 @@ +import { FC, ReactNode, createContext, useContext } from 'react' + +import { AppState } from '../AppState' + +const AppStateContext = createContext(null) +export const AppStateProvider: FC<{ + value: AppState + children: ReactNode +}> = ({ value, children }) => { + return ( + + {children} + + ) +} + +export const useAppState = () => { + const appState = useContext(AppStateContext) as unknown as AppState + return { appState } +} diff --git a/packages/state-manager/src/contexts/CanvasStateContext.tsx b/packages/state-manager/src/contexts/CanvasStateContext.tsx new file mode 100644 index 0000000..864a295 --- /dev/null +++ b/packages/state-manager/src/contexts/CanvasStateContext.tsx @@ -0,0 +1,20 @@ +import { FC, ReactNode, createContext, useContext } from 'react' + +import { PageState } from '../PageState' + +const CanvasStateContext = createContext(null) +export const CanvasStateProvider: FC<{ + value: PageState + children: ReactNode +}> = ({ value, children }) => { + return ( + + {children} + + ) +} + +export const useCanvasState = () => { + const canvasState = useContext(CanvasStateContext) as unknown as PageState + return { canvasState } +} diff --git a/packages/state-manager/src/contexts/StateManagerContext.tsx b/packages/state-manager/src/contexts/StateManagerContext.tsx deleted file mode 100644 index 8d6e1a2..0000000 --- a/packages/state-manager/src/contexts/StateManagerContext.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { FC, ReactNode, createContext, useContext } from 'react' - -import { StateManager } from '../StateManager' - -const StateManagerContext = createContext(null) -export const StateManagerProvider: FC<{ - value: StateManager - children: ReactNode -}> = ({ value, children }) => { - return ( - - {children} - - ) -} - -export const useStateManager = () => { - const stateManager = useContext( - StateManagerContext, - ) as unknown as StateManager - return { - stateManager, - appState: stateManager.app, - canvasState: stateManager.canvas, - } -} diff --git a/packages/state-manager/src/contexts/index.ts b/packages/state-manager/src/contexts/index.ts index 9d9e0a0..3d8649d 100644 --- a/packages/state-manager/src/contexts/index.ts +++ b/packages/state-manager/src/contexts/index.ts @@ -1,2 +1,3 @@ -export * from './StateManagerContext' export * from './WidgetVariablesContext' +export * from './AppStateContext' +export * from './CanvasStateContext' diff --git a/packages/state-manager/src/index.ts b/packages/state-manager/src/index.ts index 906f5bd..396a472 100644 --- a/packages/state-manager/src/index.ts +++ b/packages/state-manager/src/index.ts @@ -1,5 +1,4 @@ export { AppState } from './AppState' export { PageState } from './PageState' export { WidgetState } from './WidgetState' -export { StateManager } from './StateManager' export * from './contexts' diff --git a/websites/workspace/src/features/app/routers/App.tsx b/websites/workspace/src/features/app/routers/App.tsx index 110fda6..2988723 100644 --- a/websites/workspace/src/features/app/routers/App.tsx +++ b/websites/workspace/src/features/app/routers/App.tsx @@ -4,7 +4,7 @@ import { generateRouterPath } from '@/utils/router' import { CopyOutlined, DatabaseOutlined } from '@ant-design/icons' import { useMount } from 'ahooks' import { Layout, Menu } from 'antd' -import { ComponentProps, FC, useCallback, useState } from 'react' +import { ComponentProps, FC, useCallback, useEffect, useState } from 'react' import { Outlet, matchPath, @@ -17,6 +17,7 @@ import { AppManagerProvider } from '@modou/core' import { mcss } from '@modou/css-in-js' import { AppFile, AppManager } from '@modou/meta-vfs' import { runInAction } from '@modou/reactivity' +import { AppState, AppStateProvider } from '@modou/state-manager' import { ModuleManager } from '../components' import { AppHeader } from '../components/AppHeader' @@ -97,47 +98,58 @@ export const App: FC = () => { const isAppHome = matchPath(ROUTER_PATH.APP, pathname) - return ( - - {isAppHome ? ( - - ) : ( - - - - - - - - { - setVisibleModuleManger(false) - updateModule() - }} - module={module} - visible={visibleModuleManger} - /> - - + const [appState, setAppState] = useState() + + useEffect(() => { + if (appState?.file === appManager.app) { + return + } + setAppState(new AppState(appManager.app)) + }, [appState?.file]) + + return appState ? ( + + + {isAppHome ? ( + + ) : ( + + + + + + + + { + setVisibleModuleManger(false) + updateModule() + }} + module={module} + visible={visibleModuleManger} + /> + + + - - )} - - ) + )} + + + ) : null } const classes = { From 2c72e955e3ccecb9d1dc8312612ee3c9690f4129 Mon Sep 17 00:00:00 2001 From: liulei Date: Fri, 3 Feb 2023 09:57:22 +0800 Subject: [PATCH 63/68] =?UTF-8?q?feat:=20=E5=AE=8C=E5=96=84canvas-flow?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../flow-designer/src/FlowDesigner/index.tsx | 160 +++++---------- packages/flow-nodes/src/BranchNode/index.tsx | 11 +- packages/flow-nodes/src/StartNode/index.tsx | 8 +- .../src/_/components/FlowNodeHandles.tsx | 30 ++- .../src/_/components/FlowNodeWrapper.tsx | 28 +-- packages/flow-nodes/src/_/styles/index.ts | 16 +- packages/flow-nodes/src/index.ts | 2 + packages/meta-vfs/src/AppFile/index.ts | 26 ++- packages/meta-vfs/src/BaseFile/index.ts | 2 + packages/meta-vfs/src/FlowEdgeFile/index.ts | 22 ++ packages/meta-vfs/src/FlowFile/index.ts | 66 +++++- packages/meta-vfs/src/FlowNodeFile/index.ts | 35 +++- packages/meta-vfs/src/PageFile/index.ts | 12 ++ .../CanvasFlow}/FlowCanvas.tsx | 6 +- .../src/components/CanvasFlow/FlowList.tsx | 189 ++++++++++++++++++ .../src/components/CanvasFlow/index.tsx | 43 ++++ websites/workspace/src/components/index.ts | 1 + .../src/features/page/components/FlowList.tsx | 15 -- .../src/features/page/components/index.ts | 1 - .../src/features/page/routers/Page.tsx | 18 +- 20 files changed, 500 insertions(+), 191 deletions(-) rename websites/workspace/src/{features/page/components => components/CanvasFlow}/FlowCanvas.tsx (58%) create mode 100644 websites/workspace/src/components/CanvasFlow/FlowList.tsx create mode 100644 websites/workspace/src/components/CanvasFlow/index.tsx delete mode 100644 websites/workspace/src/features/page/components/FlowList.tsx delete mode 100644 websites/workspace/src/features/page/components/index.ts diff --git a/packages/flow-designer/src/FlowDesigner/index.tsx b/packages/flow-designer/src/FlowDesigner/index.tsx index 85d0ccb..3d007c1 100644 --- a/packages/flow-designer/src/FlowDesigner/index.tsx +++ b/packages/flow-designer/src/FlowDesigner/index.tsx @@ -1,89 +1,18 @@ -import { useClickAway, useMemoizedFn } from 'ahooks' -import { ComponentProps, FC, useRef, useState } from 'react' -import ReactFlow, { - Controls, - Edge, - Node, - addEdge, - useEdgesState, - useNodesState, -} from 'reactflow' -import 'reactflow/dist/base.css' - -import { useAppFactory } from '@modou/core' +import { useClickAway } from 'ahooks' +import { mapValues } from 'lodash' +import { FC, useMemo, useRef, useState } from 'react' +import ReactFlow, { Controls } from 'reactflow' + +import { FlowNodeMetadata, generateId, useAppFactory } from '@modou/core' import { mcss } from '@modou/css-in-js' +import { FlowNodeEnum } from '@modou/flow-nodes' +import { FlowFile } from '@modou/meta-vfs/src/FlowFile' +import { FlowNodeFile } from '@modou/meta-vfs/src/FlowNodeFile' +import { observer } from '@modou/reactivity-react' + +import { TurboEdge, TurboNode } from './components' -import { FunctionIcon, TurboEdge, TurboNode } from './components' -import { TurboNodeData } from './components/TurboNode' - -const initialNodes: Array> = [ - { - id: '1', - position: { x: 0, y: 0 }, - data: { icon: , title: 'readFile', subline: 'api.ts' }, - type: 'turbo', - }, - { - id: '2', - position: { x: 250, y: 0 }, - data: { icon: , title: 'bundle', subline: 'apiContents' }, - type: 'turbo', - }, - { - id: '3', - position: { x: 0, y: 250 }, - data: { icon: , title: 'readFile', subline: 'sdk.ts' }, - type: 'turbo', - }, - { - id: '4', - position: { x: 250, y: 250 }, - data: { icon: , title: 'bundle', subline: 'sdkContents' }, - type: 'turbo', - }, - { - id: '5', - position: { x: 500, y: 125 }, - data: { icon: , title: 'concat', subline: 'api, sdk' }, - type: 'turbo', - }, - { - id: '6', - position: { x: 750, y: 125 }, - data: { icon: , title: 'fullBundle' }, - type: 'turbo', - }, -] - -const initialEdges: Edge[] = [ - { - id: 'e1-2', - source: '1', - target: '2', - }, - { - id: 'e3-4', - source: '3', - target: '4', - }, - { - id: 'e2-5', - source: '2', - target: '5', - }, - { - id: 'e4-5', - source: '4', - target: '5', - }, - { - id: 'e5-6', - source: '5', - target: '6', - }, -] - -const nodeTypes = { +const NODE_TYPES = { turbo: TurboNode, } @@ -95,19 +24,20 @@ const defaultEdgeOptions = { type: 'turbo', markerEnd: 'edge-circle', } -export const FlowDesigner: FC = (props) => { +export const UOFlowDesigner: FC<{ file: FlowFile }> = ({ file }) => { const { appFactory } = useAppFactory() - const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes) - const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges) - - const onConnect = useMemoizedFn< - Required>['onConnect'] - >((params) => setEdges((els) => addEdge(params, els))) const contextMenuRef = useRef(null) const [contextMenuOpen, setContextMenuOpen] = useState(false) const [contextMenuPosition, setContextMenuPosition] = useState({ x: 0, y: 0 }) + const nodeTypes = useMemo(() => { + return { + ...NODE_TYPES, + ...mapValues(appFactory.flowNodeByType, (f) => f.component), + } + }, []) + useClickAway(() => { setContextMenuOpen(false) }, contextMenuRef) @@ -121,17 +51,33 @@ export const FlowDesigner: FC = (props) => { left: contextMenuPosition.x, top: contextMenuPosition.y, }} + onClick={() => { + FlowNodeFile.create( + { + ...FlowNodeMetadata.mrSchemeToDefaultJson( + appFactory.flowNodeByType[FlowNodeEnum.BRANCH_NODE].metadata + .jsonPropsSchema, + ), + id: generateId(), + position: { + x: contextMenuPosition.x, + y: contextMenuPosition.y, + }, + }, + file, + ) + }} > 123
)} { ) } +export const FlowDesigner = observer(UOFlowDesigner) + export const classes = { reactFlow: mcss` - --bg-color: rgb(17, 17, 17); - --text-color: rgb(243, 244, 246); + //--bg-color: rgb(17, 17, 17); + --bg-color: rgb(255,255,255); + //--text-color: rgb(243, 244, 246); + --text-color: rgb(0, 0, 0); --node-border-radius: 10px; --node-box-shadow: 10px 0 15px rgba(42, 138, 246, 0.3), -10px 0 15px rgba(233, 42, 103, 0.3); background-color: var(--bg-color); @@ -300,19 +250,7 @@ export const classes = { align-items: center; position: relative; } - - .react-flow__handle { - opacity: 0; - } - - .react-flow__handle.source { - right: -10px; - } - - .react-flow__handle.target { - left: -10px; - } - + .react-flow__node:focus { outline: none; } diff --git a/packages/flow-nodes/src/BranchNode/index.tsx b/packages/flow-nodes/src/BranchNode/index.tsx index ef5a758..1a33768 100644 --- a/packages/flow-nodes/src/BranchNode/index.tsx +++ b/packages/flow-nodes/src/BranchNode/index.tsx @@ -3,7 +3,10 @@ import produce from 'immer' import { type FC, memo } from 'react' import { NodeProps } from 'reactflow' -import { generateId } from '@modou/core' +import { FlowNodeMetadata, generateId } from '@modou/core' +import { FlowFile } from '@modou/meta-vfs/src/FlowFile' +import { FlowNodeFile } from '@modou/meta-vfs/src/FlowNodeFile' +import { observer } from '@modou/reactivity-react' import { mr } from '@modou/refine' import { FlowNodeHandles } from '../_/components/FlowNodeHandles' @@ -15,7 +18,9 @@ import { DEFAULT_LASE_ELSE_SCRIPT } from './constants' import { MRSchemeBranchNodeProps, branchNodeNodeMetadata } from './metadata' const _BranchNode: FC< - NodeProps>> + NodeProps< + FlowNodeFile>> + > > = (props) => { const id = useFlowNodeId() console.log('_BranchNode') @@ -109,4 +114,4 @@ const _BranchNode: FC< ) } -export const BranchNode = memo(_BranchNode) +export const BranchNode = memo(observer(_BranchNode)) diff --git a/packages/flow-nodes/src/StartNode/index.tsx b/packages/flow-nodes/src/StartNode/index.tsx index 9cf4c1d..653d1d5 100644 --- a/packages/flow-nodes/src/StartNode/index.tsx +++ b/packages/flow-nodes/src/StartNode/index.tsx @@ -1,12 +1,14 @@ import { type FC, memo } from 'react' import { NodeProps } from 'reactflow' +import { FlowNodeFile } from '@modou/meta-vfs/src/FlowNodeFile' +import { observer } from '@modou/reactivity-react' + import { FlowNodeHandles } from '../_/components/FlowNodeHandles' import { FlowNodeWrapper } from '../_/components/FlowNodeWrapper' -import { FlowNodeProps } from '../_/types' import { startNodeMetadata } from './metadata' -const _StartNode: FC> = (props) => { +const _StartNode: FC> = (props) => { return ( <> @@ -14,6 +16,6 @@ const _StartNode: FC> = (props) => { ) } -export const StartNode = memo(_StartNode) +export const StartNode = memo(observer(_StartNode)) const classes = {} diff --git a/packages/flow-nodes/src/_/components/FlowNodeHandles.tsx b/packages/flow-nodes/src/_/components/FlowNodeHandles.tsx index 5ab2e3b..aa4ebd4 100644 --- a/packages/flow-nodes/src/_/components/FlowNodeHandles.tsx +++ b/packages/flow-nodes/src/_/components/FlowNodeHandles.tsx @@ -1,27 +1,23 @@ -import { FC, useMemo } from 'react' +import { FC } from 'react' import { Handle, NodeProps, Position } from 'reactflow' +import { FlowNodeFile } from '@modou/meta-vfs/src/FlowNodeFile' +import { observer } from '@modou/reactivity-react' + import { nodeClasses } from '../styles' -import { FlowNodeProps } from '../types' -export const FlowNodeHandles: FC< - NodeProps & { +const UOFlowNodeHandles: FC< + NodeProps & { filterTargets?: (node: { name: string }) => boolean filterSources?: (node: { name: string }) => boolean } > = ({ data, isConnectable, filterTargets, filterSources }) => { - const targets = useMemo(() => { - if (!filterTargets) { - return data.targets - } - return data.targets.filter(filterTargets) - }, [data.targets, filterTargets]) - const sources = useMemo(() => { - if (!filterSources) { - return data.sources - } - return data.sources.filter(filterSources) - }, [data.sources, filterSources]) + const targets = filterTargets + ? data.meta.targets.filter(filterTargets) + : data.meta.targets + const sources = filterSources + ? data.meta.sources.filter(filterSources) + : data.meta.sources return ( <> {targets.map((target) => ( @@ -47,3 +43,5 @@ export const FlowNodeHandles: FC< ) } + +export const FlowNodeHandles = observer(UOFlowNodeHandles) diff --git a/packages/flow-nodes/src/_/components/FlowNodeWrapper.tsx b/packages/flow-nodes/src/_/components/FlowNodeWrapper.tsx index aedf775..7668fe8 100644 --- a/packages/flow-nodes/src/_/components/FlowNodeWrapper.tsx +++ b/packages/flow-nodes/src/_/components/FlowNodeWrapper.tsx @@ -4,20 +4,19 @@ import { NodeProps } from 'reactflow' import { type FlowNodeMetadata } from '@modou/core' import { cx, mcss } from '@modou/css-in-js' - -import { useFlowNodeId } from '../hooks' -import { FlowNodeProps } from '../types' +import { FlowNodeFile } from '@modou/meta-vfs/src/FlowNodeFile' +import { runInAction } from '@modou/reactivity' +import { observer } from '@modou/reactivity-react' enum NameMode { Edit, Readonly, } -export const FlowNodeWrapper: FC<{ +const UOFlowNodeWrapper: FC<{ children?: ReactNode meta: FlowNodeMetadata - node: NodeProps + node: NodeProps }> = ({ children, meta, node }) => { - const id = useFlowNodeId() const [nameMode, setNameMode] = useState(NameMode.Readonly) return (
@@ -34,26 +33,19 @@ export const FlowNodeWrapper: FC<{ className={classes.readOnlyName} onClick={() => setNameMode(NameMode.Edit)} > - {node.data.name} + {node.data.meta.name} )} {nameMode === NameMode.Edit && ( setNameMode(NameMode.Readonly)} // TODO 失去焦点的时候保存 onChange={(e) => { - node.data._onChangeNode({ - id, - data: { - ...node.data, - name: e.target.value, - props: { - ...node.data.props, - }, - }, + runInAction(() => { + node.data.meta.name = e.target.value }) }} /> @@ -67,6 +59,8 @@ export const FlowNodeWrapper: FC<{ ) } +export const FlowNodeWrapper = observer(UOFlowNodeWrapper) + const classes = { wrapper: mcss` border: 1px solid #1677ff; diff --git a/packages/flow-nodes/src/_/styles/index.ts b/packages/flow-nodes/src/_/styles/index.ts index c1d7ebe..a2cd97c 100644 --- a/packages/flow-nodes/src/_/styles/index.ts +++ b/packages/flow-nodes/src/_/styles/index.ts @@ -10,9 +10,11 @@ export const nodeClasses = { // box-shadow: var(--node-box-shadow); // `, nodeTargetPort: mcss` - background-color: #535bf2; - height: 10px; - width: 10px; + &.react-flow__handle{ + background-color: #535bf2; + height: 10px; + width: 10px; + } &.react-flow__handle-left{ left: -12px; } @@ -21,9 +23,11 @@ export const nodeClasses = { } `, nodeSourcePort: mcss` - background-color: seagreen; - height: 10px; - width: 10px; + &.react-flow__handle{ + background-color: seagreen; + height: 10px; + width: 10px; + } &.react-flow__handle-right{ right: -12px; } diff --git a/packages/flow-nodes/src/index.ts b/packages/flow-nodes/src/index.ts index 44ea5d7..8f99953 100644 --- a/packages/flow-nodes/src/index.ts +++ b/packages/flow-nodes/src/index.ts @@ -13,3 +13,5 @@ export * from './LoopNode/interpreter' export * from './BranchNode' export * from './BranchNode/metadata' export * from './BranchNode/interpreter' + +export { FlowNodeEnum } from './_/types' diff --git a/packages/meta-vfs/src/AppFile/index.ts b/packages/meta-vfs/src/AppFile/index.ts index 9364ff6..fe84eea 100644 --- a/packages/meta-vfs/src/AppFile/index.ts +++ b/packages/meta-vfs/src/AppFile/index.ts @@ -11,6 +11,7 @@ import { import { BaseFile, BaseFileMap, BaseFileMete } from '../BaseFile' import { EntityFile } from '../EntityFile' import { EntityRelationFile } from '../EntityRelationFile' +import { FlowFile } from '../FlowFile' import { PageFile } from '../PageFile' import { emitters } from '../event-bus' import { FileTypeEnum } from '../types' @@ -19,6 +20,7 @@ export type AppFileMeta = BaseFileMete interface FileMap extends BaseFileMap { readonly pages: PageFile[] readonly entities: EntityFile[] + readonly flows: FlowFile[] } export class AppFile extends BaseFile { protected constructor(meta: AppFileMeta) { @@ -52,6 +54,7 @@ export class AppFile extends BaseFile { subFileMap: FileMap = { pages: [], entities: [], + flows: [], } private readonly persistMeta = () => { @@ -77,7 +80,7 @@ export class AppFile extends BaseFile { }) } - deletePage(pageId: string) { + deletePage = (pageId: string) => { const oldPages = [...this.subFileMap.pages] this.subFileMap.pages.length = 0 this.subFileMap.pages.push( @@ -85,6 +88,25 @@ export class AppFile extends BaseFile { ) } + get flows() { + return this.subFileMap.flows + } + + set flows(flows) { + runInAction(() => { + this.subFileMap.flows.length = 0 + this.subFileMap.flows.push(...flows) + }) + } + + deleteFlow = (flowId: string) => { + const oldFlows = [...this.subFileMap.flows] + this.subFileMap.flows.length = 0 + this.subFileMap.flows.push( + ...oldFlows.filter((flow) => flow.meta.id !== flowId), + ) + } + get entities() { return this.subFileMap.entities } @@ -100,7 +122,7 @@ export class AppFile extends BaseFile { return keyBy(this.entities, (entity) => entity.meta.id) } - deleteEntity(entityId: string) { + deleteEntity = (entityId: string) => { const oldEntities = [...this.subFileMap.entities] this.subFileMap.entities.length = 0 this.subFileMap.entities.push( diff --git a/packages/meta-vfs/src/BaseFile/index.ts b/packages/meta-vfs/src/BaseFile/index.ts index cfdcf35..f990158 100644 --- a/packages/meta-vfs/src/BaseFile/index.ts +++ b/packages/meta-vfs/src/BaseFile/index.ts @@ -86,6 +86,8 @@ export abstract class BaseFile< }, ) this.disposer = () => { + // 文件被删除了 + emitters.emit('updateFileMeta', null) disposer() disposerSubFiles() } diff --git a/packages/meta-vfs/src/FlowEdgeFile/index.ts b/packages/meta-vfs/src/FlowEdgeFile/index.ts index 8b17f91..51865f9 100644 --- a/packages/meta-vfs/src/FlowEdgeFile/index.ts +++ b/packages/meta-vfs/src/FlowEdgeFile/index.ts @@ -1,4 +1,5 @@ import { omit } from 'lodash' +import { Edge } from 'reactflow' import { FileTypeEnum } from '@modou/meta-vfs' import { makeObservable, observable, runInAction } from '@modou/reactivity' @@ -25,6 +26,27 @@ export class FlowEdgeFile extends BaseFile<{}, FlowEdgeFileMeta, FlowFile> { }) } + // TODO 添加 private 参考mobx文档 是支持的 + + tempMeta: Partial = {} + get reactFlowMeta(): Edge { + return { + ...this.tempMeta, + ...this.meta, + data: this, + } + } + + set reactFlowMeta(edge: Edge) { + runInAction(() => { + this.meta.source = edge.source + this.meta.target = edge.target + this.meta.sourceHandle = edge.sourceHandle! + this.meta.targetHandle = edge.targetHandle! + this.tempMeta = edge + }) + } + subFileMap = {} toJSON() { return { diff --git a/packages/meta-vfs/src/FlowFile/index.ts b/packages/meta-vfs/src/FlowFile/index.ts index 46fc523..7948ed7 100644 --- a/packages/meta-vfs/src/FlowFile/index.ts +++ b/packages/meta-vfs/src/FlowFile/index.ts @@ -1,4 +1,13 @@ import { omit } from 'lodash' +import { + Connection, + type Edge, + EdgeChange, + type NodeChange, + addEdge, + applyEdgeChanges, + applyNodeChanges, +} from 'reactflow' import { FileTypeEnum, PageFile } from '@modou/meta-vfs' import { @@ -28,6 +37,7 @@ export class FlowFile extends BaseFile { subFileMap: observable, flowNodes: computed, flowEdges: computed, + reactFlowNodes: computed.struct, }) } @@ -44,6 +54,60 @@ export class FlowFile extends BaseFile { return this.subFileMap.flowEdges } + get reactFlowNodes() { + return this.flowNodes.map((n) => n.reactFlowMeta) + } + + onReactFlowNodesChange = (changes: NodeChange[]) => { + runInAction(() => { + const res = applyNodeChanges(changes, this.reactFlowNodes) + this.subFileMap.flowNodes.length = 0 + res.forEach((node) => { + node.data.reactFlowMeta = node + this.subFileMap.flowNodes.push(node.data) + }) + }) + } + + get reactFlowEdges() { + console.log('this.flowEdges', this.flowEdges) + return this.flowEdges.map((e) => e.reactFlowMeta) + } + + private readonly updateReactFlowEdges = ( + edges: Array>, + ) => { + runInAction(() => { + this.subFileMap.flowEdges.length = 0 + edges.forEach((edge) => { + if (!edge.data) { + edge.data = FlowEdgeFile.create( + { + name: '', + id: edge.id, + source: edge.source, + sourceHandle: edge.sourceHandle!, + target: edge.target, + targetHandle: edge.targetHandle!, + }, + this, + ) + } + this.subFileMap.flowEdges.push(edge.data) + }) + }) + } + + onReactFlowEdgesChange = (changes: EdgeChange[]) => { + const edges = applyEdgeChanges(changes, this.reactFlowEdges) + this.updateReactFlowEdges(edges) + } + + onReactFlowConnect = (connection: Connection) => { + const edges = addEdge(connection, this.reactFlowEdges) + this.updateReactFlowEdges(edges) + } + toJSON() { return { ...this.meta, @@ -53,7 +117,7 @@ export class FlowFile extends BaseFile { } // TODO 所有 version 提到 create 函数内部 - static create(meta: FlowFileMeta, parentFile: PageFile) { + static create(meta: Omit, parentFile: PageFile) { return runInAction(() => { const flowFile = new FlowFile( { diff --git a/packages/meta-vfs/src/FlowNodeFile/index.ts b/packages/meta-vfs/src/FlowNodeFile/index.ts index 0f1cbb1..ad1b637 100644 --- a/packages/meta-vfs/src/FlowNodeFile/index.ts +++ b/packages/meta-vfs/src/FlowNodeFile/index.ts @@ -1,8 +1,14 @@ import { omit } from 'lodash' +import { type Node } from 'reactflow' import { FlowNodeBaseProps } from '@modou/core' import { FileTypeEnum } from '@modou/meta-vfs' -import { makeObservable, observable, runInAction } from '@modou/reactivity' +import { + computed, + makeObservable, + observable, + runInAction, +} from '@modou/reactivity' import { BaseFile, BaseFileMete } from '../BaseFile' import { FlowFile } from '../FlowFile' @@ -10,8 +16,10 @@ import { FlowFile } from '../FlowFile' export type FlowNodeFileMeta = BaseFileMete -export class FlowNodeFile extends BaseFile<{}, FlowNodeFileMeta, FlowFile> { - constructor(meta: FlowNodeFileMeta, parentFile: FlowFile) { +export class FlowNodeFile< + T extends FlowNodeFileMeta = FlowNodeFileMeta, +> extends BaseFile<{}, T, FlowFile> { + constructor(meta: T, parentFile: FlowFile) { super({ fileType: FileTypeEnum.FlowNode, meta, @@ -19,6 +27,27 @@ export class FlowNodeFile extends BaseFile<{}, FlowNodeFileMeta, FlowFile> { }) makeObservable(this, { subFileMap: observable, + tempMeta: observable, + reactFlowMeta: computed.struct, + }) + } + + // TODO 添加 private 参考mobx文档 是支持的 + tempMeta: Partial = {} + get reactFlowMeta(): Node { + return { + ...this.tempMeta, + id: this.meta.id, + type: this.meta.type, + position: this.meta.position, + data: this, + } + } + + set reactFlowMeta(node: Node) { + runInAction(() => { + this.meta.position = node.position + this.tempMeta = node }) } diff --git a/packages/meta-vfs/src/PageFile/index.ts b/packages/meta-vfs/src/PageFile/index.ts index 359ca21..4cc78cc 100644 --- a/packages/meta-vfs/src/PageFile/index.ts +++ b/packages/meta-vfs/src/PageFile/index.ts @@ -63,6 +63,18 @@ export class PageFile extends BaseFile { return this.subFileMap.flows } + get flowMap() { + return keyBy(this.subFileMap.flows, (flow) => flow.meta.id) + } + + deleteFlow = (flowId: string) => { + const oldFlows = [...this.subFileMap.flows] + this.subFileMap.flows.length = 0 + this.subFileMap.flows.push( + ...oldFlows.filter((flow) => flow.meta.id !== flowId), + ) + } + get widgetMap() { return keyBy(this.subFileMap.widgets, (widget) => widget.meta.id) } diff --git a/websites/workspace/src/features/page/components/FlowCanvas.tsx b/websites/workspace/src/components/CanvasFlow/FlowCanvas.tsx similarity index 58% rename from websites/workspace/src/features/page/components/FlowCanvas.tsx rename to websites/workspace/src/components/CanvasFlow/FlowCanvas.tsx index 803d24e..82a6ba4 100644 --- a/websites/workspace/src/features/page/components/FlowCanvas.tsx +++ b/websites/workspace/src/components/CanvasFlow/FlowCanvas.tsx @@ -2,11 +2,12 @@ import { FC } from 'react' import { mcss } from '@modou/css-in-js' import { FlowDesigner } from '@modou/flow-designer' +import { FlowFile } from '@modou/meta-vfs/src/FlowFile' -export const FlowCanvas: FC = () => { +export const FlowCanvas: FC<{ file: FlowFile }> = ({ file }) => { return (
- +
) } @@ -15,5 +16,6 @@ const classes = { wrapper: mcss` height: 100%; flex: 1; + border: 1px solid red; `, } diff --git a/websites/workspace/src/components/CanvasFlow/FlowList.tsx b/websites/workspace/src/components/CanvasFlow/FlowList.tsx new file mode 100644 index 0000000..3364feb --- /dev/null +++ b/websites/workspace/src/components/CanvasFlow/FlowList.tsx @@ -0,0 +1,189 @@ +import { MoreOutlined, PlusOutlined } from '@ant-design/icons' +import { ModalForm, ProFormText } from '@ant-design/pro-components' +import { Button, Dropdown, Form, List, Typography } from 'antd' +import { ComponentProps, Dispatch, FC, SetStateAction, useContext } from 'react' +import { useParams } from 'react-router-dom' + +import { + AppFactoryContext, + FlowNodeMetadata, + generateId, + useAppManager, +} from '@modou/core' +import { mcss } from '@modou/css-in-js' +import { FlowNodeEnum } from '@modou/flow-nodes' +import { FlowFile, FlowFileMeta } from '@modou/meta-vfs/src/FlowFile' +import { FlowNodeFile } from '@modou/meta-vfs/src/FlowNodeFile' +import { Observer, observer } from '@modou/reactivity-react' + +import { PageRouterParamsKey } from '../../types' + +enum FlowActionEnum { + Delete = 'Delete', + Copy = 'Copy', +} +const _FlowList: FC<{ + activeFlowId: string + setActiveFlowId: Dispatch> +}> = ({ activeFlowId, setActiveFlowId }) => { + const { appManager } = useAppManager() + const { pageId } = useParams() + const page = appManager.pageMap.get(pageId as string)! + + const [form] = Form.useForm>() + + const renderListItem: ComponentProps>['renderItem'] = ( + flow, + ) => ( + + {() => ( + { + setActiveFlowId(flow.meta.id) + }} + > +
+ {flow.meta.id === activeFlowId ? ( + {flow.meta.name} + ) : ( + {flow.meta.name} + )} + { + switch (key) { + case FlowActionEnum.Delete: + page.deleteFlow(flow.meta.id) + break + default: + } + }, + items: [ + { + label: 复制, + key: FlowActionEnum.Copy, + }, + { + label: ( + 删除 + ), + key: FlowActionEnum.Delete, + }, + ], + }} + > + + +
+
+ )} +
+ ) + const appFactory = useContext(AppFactoryContext) + + return ( +
+
+ > + form={form} + layout="horizontal" + title="创建流" + modalProps={{ + mask: false, + }} + onFinish={async (formData) => { + await form.validateFields() + const newFlow = FlowFile.create( + { + id: generateId(), + name: formData.name, + }, + page, + ) + FlowNodeFile.create( + { + ...FlowNodeMetadata.mrSchemeToDefaultJson( + appFactory.flowNodeByType[FlowNodeEnum.START_NODE].metadata + .jsonPropsSchema, + ), + id: generateId(), + position: { + x: 100, + y: 100, + }, + }, + newFlow, + ) + form.resetFields() + return true + }} + trigger={ + + } + > + + +
+
+ item.meta.id} + renderItem={renderListItem} + /> +
+
+ ) +} +export const FlowList = observer(_FlowList) + +const classes = { + wrapper: mcss` + width: 220px; + border: 1px solid green; + background-color: white; + padding: 0 16px 16px; + `, + createWrapper: mcss` + text-align: right; + `, + listItem: mcss` + margin-left: -16px; + margin-right: -16px; + padding-left: 16px; + padding-right: 16px; + border: none !important; + cursor: default; + &:hover { + background-color: rgba(0, 0, 0, 0.1); + .mm_p-list_item_more_action { + display: block !important; + } + } + `, + listItemContent: mcss` + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + a { + cursor: default !important; + } + `, + moreAction: mcss` + display: none; + `, +} diff --git a/websites/workspace/src/components/CanvasFlow/index.tsx b/websites/workspace/src/components/CanvasFlow/index.tsx new file mode 100644 index 0000000..b0d30df --- /dev/null +++ b/websites/workspace/src/components/CanvasFlow/index.tsx @@ -0,0 +1,43 @@ +import { Empty } from 'antd' +import { FC, useState } from 'react' + +import { mcss } from '@modou/css-in-js' +import { PageFile } from '@modou/meta-vfs' +import { observer } from '@modou/reactivity-react' + +import { FlowCanvas } from './FlowCanvas' +import { FlowList } from './FlowList' + +export const UOCanvasFlow: FC<{ + parentFile: PageFile +}> = ({ parentFile }) => { + const [activeFlowId, setActiveFlowId] = useState('agdhgoasmiht') + const flowFile = parentFile.flowMap[activeFlowId] + return ( +
+ + {flowFile ? ( + + ) : ( + + )} +
+ ) +} +export const CanvasFlow = observer(UOCanvasFlow) + +const classes = { + wrapper: mcss` + height: 100%; + width: 100%; + display: flex; + flex-direction: row; + `, + empty: mcss` + height: 100%; + flex: 1; + display: flex; + align-items: center; + justify-content: center; + `, +} diff --git a/websites/workspace/src/components/index.ts b/websites/workspace/src/components/index.ts index e0a4a4b..8e0f5ad 100644 --- a/websites/workspace/src/components/index.ts +++ b/websites/workspace/src/components/index.ts @@ -1,2 +1,3 @@ export * from './AppSpin' export * from './IconFont' +export * from './CanvasFlow' diff --git a/websites/workspace/src/features/page/components/FlowList.tsx b/websites/workspace/src/features/page/components/FlowList.tsx deleted file mode 100644 index 1766ae0..0000000 --- a/websites/workspace/src/features/page/components/FlowList.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { FC } from 'react' - -import { mcss } from '@modou/css-in-js' - -export const FlowList: FC = () => { - return
FlowList
-} - -const classes = { - wrapper: mcss` - width: 220px; - border: 1px solid green; - background-color: white; - `, -} diff --git a/websites/workspace/src/features/page/components/index.ts b/websites/workspace/src/features/page/components/index.ts deleted file mode 100644 index 3981c8c..0000000 --- a/websites/workspace/src/features/page/components/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { FlowCanvas } from './FlowCanvas' diff --git a/websites/workspace/src/features/page/routers/Page.tsx b/websites/workspace/src/features/page/routers/Page.tsx index 1df75d0..a6a046a 100644 --- a/websites/workspace/src/features/page/routers/Page.tsx +++ b/websites/workspace/src/features/page/routers/Page.tsx @@ -16,8 +16,7 @@ import { mcss } from '@modou/css-in-js' import { observer } from '@modou/reactivity-react' import { SimulatorPC } from '@modou/simulator' -import { FlowCanvas } from '../components' -import { FlowList } from '../components/FlowList' +import { CanvasFlow } from '../../../components' const _Page: FC = () => { const { pageId, appId } = useParams() @@ -39,23 +38,20 @@ const _Page: FC = () => { } }, [appId, appManager.app.pages, navigate, page]) - return ( + return page ? ( - {page && ( - - - - )} + + + - - + - ) + ) : null } export const Page = observer(_Page) From 35625817f1a99222595990dea2fed378687af695 Mon Sep 17 00:00:00 2001 From: liulei Date: Tue, 14 Feb 2023 01:44:29 +0800 Subject: [PATCH 64/68] =?UTF-8?q?feat(flow-node):=20=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E6=B5=81=E8=8A=82=E7=82=B9=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/flow-nodes/src/BranchNode/index.tsx | 85 +++++++++---------- packages/flow-nodes/src/LoopNode/index.tsx | 48 ++++++----- .../flow-nodes/src/RunScriptNode/index.tsx | 33 ++++--- packages/flow-nodes/src/StartNode/index.tsx | 12 ++- .../src/_/components/FlowNodeHandles.tsx | 21 ++--- .../src/_/components/FlowNodeWrapper.tsx | 2 +- 6 files changed, 100 insertions(+), 101 deletions(-) diff --git a/packages/flow-nodes/src/BranchNode/index.tsx b/packages/flow-nodes/src/BranchNode/index.tsx index 1a33768..0fc4b9c 100644 --- a/packages/flow-nodes/src/BranchNode/index.tsx +++ b/packages/flow-nodes/src/BranchNode/index.tsx @@ -1,35 +1,34 @@ import { Button, Space } from 'antd' -import produce from 'immer' -import { type FC, memo } from 'react' +import { type FC } from 'react' import { NodeProps } from 'reactflow' -import { FlowNodeMetadata, generateId } from '@modou/core' -import { FlowFile } from '@modou/meta-vfs/src/FlowFile' -import { FlowNodeFile } from '@modou/meta-vfs/src/FlowNodeFile' +import { generateId } from '@modou/core' +import { + FlowNodeFile, + FlowNodeFileMeta, +} from '@modou/meta-vfs/src/FlowNodeFile' +import { runInAction } from '@modou/reactivity' import { observer } from '@modou/reactivity-react' import { mr } from '@modou/refine' import { FlowNodeHandles } from '../_/components/FlowNodeHandles' import { FlowNodeWrapper } from '../_/components/FlowNodeWrapper' -import { useFlowNodeId } from '../_/hooks' -import { FlowNodeProps } from '../_/types' import { CaseBlock } from './CaseBlock' import { DEFAULT_LASE_ELSE_SCRIPT } from './constants' import { MRSchemeBranchNodeProps, branchNodeNodeMetadata } from './metadata' const _BranchNode: FC< NodeProps< - FlowNodeFile>> + FlowNodeFile>> > > = (props) => { - const id = useFlowNodeId() console.log('_BranchNode') return ( <> - {props.data.props.branches.map((branch, index, branches) => ( + {props.data.meta.props.branches.map((branch, index, branches) => ( { - props.data._onChangeNode({ - id, - data: { - ...props.data, - props: { - ...props.data.props, - branches: props.data.props.branches.map((br) => { - if (br.port !== branch.port) { - return br - } - return branch - }), - }, - }, + runInAction(() => { + props.data.meta.props.branches = + props.data.meta.props.branches.map((br) => { + if (br.port !== branch.port) { + return br + } + return branch + }) }) }} onDeleteBranch={(branch) => { // TODO 删除 branch 的同时删除相关的边 - props.data._onChangeNode({ - id, - data: produce(props.data, (draft) => { - draft.props.branches = draft.props.branches + runInAction(() => { + props.data.meta.props.branches = + props.data.meta.props.branches .filter((br) => br.port !== branch.port) .map((br, index) => { if ( @@ -72,10 +64,9 @@ const _BranchNode: FC< } return br }) - draft.sources = draft.sources.filter( - (s) => s.name !== branch.port, - ) - }), + props.data.meta.sources = props.data.meta.sources.filter( + (s) => s.name !== branch.port, + ) }) }} /> @@ -85,24 +76,22 @@ const _BranchNode: FC< type="primary" onClick={() => { const portId = generateId() - props.data._onChangeNode({ - id, - data: produce(props.data, (draft) => { - draft.sources.push({ - name: portId, - }) - draft.props.branches = draft.props.branches.map((branch) => ({ + runInAction(() => { + props.data.meta.sources.push({ + name: portId, + }) + props.data.meta.props.branches = + props.data.meta.props.branches.map((branch) => ({ ...branch, script: branch.script === DEFAULT_LASE_ELSE_SCRIPT ? '' : branch.script, })) - draft.props.branches.push({ - port: portId, - script: DEFAULT_LASE_ELSE_SCRIPT, - }) - }), + props.data.meta.props.branches.push({ + port: portId, + script: DEFAULT_LASE_ELSE_SCRIPT, + }) }) }} > @@ -110,8 +99,12 @@ const _BranchNode: FC< - false} /> + ) } -export const BranchNode = memo(observer(_BranchNode)) +export const BranchNode = observer(_BranchNode) diff --git a/packages/flow-nodes/src/LoopNode/index.tsx b/packages/flow-nodes/src/LoopNode/index.tsx index 1a27329..5e69abc 100644 --- a/packages/flow-nodes/src/LoopNode/index.tsx +++ b/packages/flow-nodes/src/LoopNode/index.tsx @@ -1,25 +1,29 @@ -import produce from 'immer' -import { type FC, memo, useMemo } from 'react' +import { type FC } from 'react' import { Handle, NodeProps, Position } from 'reactflow' import { CodeEditor, CodeEditorModeEnum } from '@modou/code-editor' +import { + FlowNodeFile, + FlowNodeFileMeta, +} from '@modou/meta-vfs/src/FlowNodeFile' +import { runInAction } from '@modou/reactivity' +import { observer } from '@modou/reactivity-react' import { mr } from '@modou/refine' import { FlowNodeHandles } from '../_/components/FlowNodeHandles' import { FlowNodeWrapper } from '../_/components/FlowNodeWrapper' -import { useFlowNodeId } from '../_/hooks' import { nodeClasses } from '../_/styles' -import { FlowNodeProps, ScopedFlowNodePortNameEnum } from '../_/types' +import { ScopedFlowNodePortNameEnum } from '../_/types' import { MRSchemeLoopNodeProps, loopNodeMetadata } from './metadata' -type LoopNodeProps = mr.infer -const _LoopNode: FC>> = (props) => { - const id = useFlowNodeId() - const loopBodyPort = useMemo(() => { - return props.data.sources.find( - (s) => s.name === ScopedFlowNodePortNameEnum.LOOP_BODY, - )! - }, [props.data.sources]) +const _LoopNode: FC< + NodeProps< + FlowNodeFile>> + > +> = (props) => { + const loopBodyPort = props.data.meta.sources.find( + (s) => s.name === ScopedFlowNodePortNameEnum.LOOP_BODY, + )! return ( <> @@ -27,23 +31,21 @@ const _LoopNode: FC>> = (props) => {
循环体
{ - props.data._onChangeNode({ - id, - data: produce(props.data, (draft) => { - draft.props.iterable = value - }), + runInAction(() => { + props.data.meta.props.iterable = value }) }} />
- port.name !== ScopedFlowNodePortNameEnum.LOOP_BODY - } + sources={props.data.meta.sources.filter( + (port) => port.name !== ScopedFlowNodePortNameEnum.LOOP_BODY, + )} + targets={props.data.meta.targets} + isConnectable={props.isConnectable} /> >> = (props) => { ) } -export const LoopNode = memo(_LoopNode) +export const LoopNode = observer(_LoopNode) diff --git a/packages/flow-nodes/src/RunScriptNode/index.tsx b/packages/flow-nodes/src/RunScriptNode/index.tsx index 82ee96e..9b2db4f 100644 --- a/packages/flow-nodes/src/RunScriptNode/index.tsx +++ b/packages/flow-nodes/src/RunScriptNode/index.tsx @@ -1,20 +1,24 @@ -import produce from 'immer' -import { type FC, memo } from 'react' +import { type FC } from 'react' import { NodeProps } from 'reactflow' import { CodeEditor, CodeEditorModeEnum } from '@modou/code-editor' +import { + FlowNodeFile, + FlowNodeFileMeta, +} from '@modou/meta-vfs/src/FlowNodeFile' +import { runInAction } from '@modou/reactivity' +import { observer } from '@modou/reactivity-react' import { mr } from '@modou/refine' import { FlowNodeHandles } from '../_/components/FlowNodeHandles' import { FlowNodeWrapper } from '../_/components/FlowNodeWrapper' -import { useFlowNodeId } from '../_/hooks' -import { FlowNodeProps } from '../_/types' import { MRSchemeRunScriptNodeProps, runScriptNodeMetadata } from './metadata' const _RunScriptNode: FC< - NodeProps>> + NodeProps< + FlowNodeFile>> + > > = (props) => { - const id = useFlowNodeId() console.log('_RunScriptNode') return ( @@ -22,19 +26,20 @@ const _RunScriptNode: FC< { - props.data._onChangeNode({ - id, - data: produce(props.data, (draft) => { - draft.props.script = value - }), + runInAction(() => { + props.data.meta.props.script = value }) }} /> - + ) } -export const RunScriptNode = memo(_RunScriptNode) +export const RunScriptNode = observer(_RunScriptNode) diff --git a/packages/flow-nodes/src/StartNode/index.tsx b/packages/flow-nodes/src/StartNode/index.tsx index 653d1d5..f87244a 100644 --- a/packages/flow-nodes/src/StartNode/index.tsx +++ b/packages/flow-nodes/src/StartNode/index.tsx @@ -1,4 +1,4 @@ -import { type FC, memo } from 'react' +import { type FC } from 'react' import { NodeProps } from 'reactflow' import { FlowNodeFile } from '@modou/meta-vfs/src/FlowNodeFile' @@ -12,10 +12,14 @@ const _StartNode: FC> = (props) => { return ( <> - + ) } -export const StartNode = memo(observer(_StartNode)) +export const StartNode = observer(_StartNode) -const classes = {} +// const classes = {} diff --git a/packages/flow-nodes/src/_/components/FlowNodeHandles.tsx b/packages/flow-nodes/src/_/components/FlowNodeHandles.tsx index aa4ebd4..70d5055 100644 --- a/packages/flow-nodes/src/_/components/FlowNodeHandles.tsx +++ b/packages/flow-nodes/src/_/components/FlowNodeHandles.tsx @@ -1,23 +1,18 @@ import { FC } from 'react' -import { Handle, NodeProps, Position } from 'reactflow' +import { Handle, Position } from 'reactflow' import { FlowNodeFile } from '@modou/meta-vfs/src/FlowNodeFile' import { observer } from '@modou/reactivity-react' import { nodeClasses } from '../styles' -const UOFlowNodeHandles: FC< - NodeProps & { - filterTargets?: (node: { name: string }) => boolean - filterSources?: (node: { name: string }) => boolean - } -> = ({ data, isConnectable, filterTargets, filterSources }) => { - const targets = filterTargets - ? data.meta.targets.filter(filterTargets) - : data.meta.targets - const sources = filterSources - ? data.meta.sources.filter(filterSources) - : data.meta.sources +type Targets = FlowNodeFile['meta']['targets'] +type Sources = FlowNodeFile['meta']['sources'] +const UOFlowNodeHandles: FC<{ + targets: Targets + sources: Sources + isConnectable: boolean +}> = ({ targets, sources, isConnectable }) => { return ( <> {targets.map((target) => ( diff --git a/packages/flow-nodes/src/_/components/FlowNodeWrapper.tsx b/packages/flow-nodes/src/_/components/FlowNodeWrapper.tsx index 7668fe8..7e84092 100644 --- a/packages/flow-nodes/src/_/components/FlowNodeWrapper.tsx +++ b/packages/flow-nodes/src/_/components/FlowNodeWrapper.tsx @@ -15,7 +15,7 @@ enum NameMode { const UOFlowNodeWrapper: FC<{ children?: ReactNode meta: FlowNodeMetadata - node: NodeProps + node: NodeProps> }> = ({ children, meta, node }) => { const [nameMode, setNameMode] = useState(NameMode.Readonly) return ( From f057a8d2a09c856a962dc3d813c02b0be668ad9f Mon Sep 17 00:00:00 2001 From: liulei Date: Mon, 20 Feb 2023 02:19:27 +0800 Subject: [PATCH 65/68] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E7=9B=AE=E5=BD=95=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + packages/asset-vfs/src/AssetVFS.ts | 18 ++ .../src/app-factory}/AppFactoryContext.ts | 6 +- .../src/app-factory/index.ts | 10 +- packages/asset-vfs/src/index.ts | 23 +-- .../src/components/CanvasDesignerCanvas.tsx | 2 +- .../components/CanvasDesignerPropsPanel.tsx | 2 +- .../CanvasDesignerWidgetStencil.tsx | 5 +- .../indicatoir/DropIndicator.tsx | 3 +- .../indicatoir/SelectedIndicator.tsx | 2 +- .../indicatoir/SelectedToolBox.tsx | 2 +- .../src/hooks/usePageOutlineTree.tsx | 10 +- .../src/hooks/useWidgetDrop.ts | 2 +- packages/core/package.json | 1 - .../contexts/WidgetsDeepPositionContext.ts | 0 packages/core/src/contexts/index.ts | 2 - .../core/src/flow-node/FlowNodeMetadata.ts | 2 +- packages/core/src/index.ts | 2 - packages/core/src/utils/index.ts | 7 - .../FlowDesigner/components/ContextMenu.tsx | 95 +++++++++ .../flow-designer/src/FlowDesigner/index.tsx | 185 ++++++++---------- packages/flow-nodes/src/BranchNode/index.tsx | 7 +- .../flow-nodes/src/BranchNode/interpreter.ts | 2 +- packages/flow-nodes/src/LoopNode/index.tsx | 4 +- .../flow-nodes/src/RunScriptNode/index.tsx | 4 +- packages/flow-nodes/src/StartNode/index.tsx | 4 +- .../src/_/components/FlowNodeWrapper.tsx | 28 ++- .../src}/AppManagerContext.tsx | 2 +- packages/meta-vfs/src/FlowFile/index.ts | 25 ++- packages/meta-vfs/src/index.ts | 2 + .../render/src/components/ReactRender.tsx | 3 +- .../src/components/ReactRenderTolerant.tsx | 2 +- .../render/src/components/WidgetVirtual.tsx | 3 +- packages/shared/package.json | 15 ++ packages/shared/src/dom/index.ts | 15 ++ packages/shared/src/index.ts | 8 + pnpm-lock.yaml | 14 ++ .../src/components/CanvasFlow/FlowList.tsx | 10 +- .../src/features/app/components/AppHome.tsx | 2 +- .../app/components/ModuleManagerPage.tsx | 10 +- .../src/features/app/routers/App.tsx | 3 +- .../src/features/app/routers/mock.ts | 3 +- .../features/entity/components/EntitiesER.tsx | 2 +- .../entity/components/EntitiesList.tsx | 3 +- .../entity/components/EntityFieldCreator.tsx | 3 +- .../entity/components/EntityFields.tsx | 3 +- .../entity/components/EntityModuleActions.tsx | 2 +- .../features/entity/hooks/useEntityCreator.ts | 4 +- .../src/features/entity/routers/Entity.tsx | 2 +- .../src/features/page/routers/Page.tsx | 7 +- 50 files changed, 371 insertions(+), 201 deletions(-) create mode 100644 packages/asset-vfs/src/AssetVFS.ts rename packages/{core/src/contexts => asset-vfs/src/app-factory}/AppFactoryContext.ts (95%) rename packages/{core => asset-vfs}/src/app-factory/index.ts (93%) delete mode 100644 packages/core/src/contexts/WidgetsDeepPositionContext.ts delete mode 100644 packages/core/src/contexts/index.ts create mode 100644 packages/flow-designer/src/FlowDesigner/components/ContextMenu.tsx rename packages/{core/src/contexts => meta-vfs/src}/AppManagerContext.tsx (89%) create mode 100644 packages/shared/package.json create mode 100644 packages/shared/src/dom/index.ts create mode 100644 packages/shared/src/index.ts diff --git a/package.json b/package.json index f5417ee..1f81c4a 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,7 @@ "@modou/refine": "workspace:^1.0.0", "@modou/render": "workspace:^1.0.0", "@modou/setters": "workspace:^1.0.0", + "@modou/shared": "workspace:^1.0.0", "@modou/simulator": "workspace:^1.0.0", "@modou/state-manager": "workspace:^0.0.1", "@modou/widgets-antd": "workspace:^1.0.0", diff --git a/packages/asset-vfs/src/AssetVFS.ts b/packages/asset-vfs/src/AssetVFS.ts new file mode 100644 index 0000000..3c4bc38 --- /dev/null +++ b/packages/asset-vfs/src/AssetVFS.ts @@ -0,0 +1,18 @@ +import { AppFactory } from '@modou/core' +import { makeAutoObservable } from '@modou/reactivity' + +export class AssetVFS { + constructor({ appFactory }: { appFactory: AppFactory }) { + this.appFactory = appFactory + if (AssetVFS.instance) { + return AssetVFS.instance + } else { + makeAutoObservable(this) + AssetVFS.instance = this + } + } + + appFactory: AppFactory + + private static instance: AssetVFS +} diff --git a/packages/core/src/contexts/AppFactoryContext.ts b/packages/asset-vfs/src/app-factory/AppFactoryContext.ts similarity index 95% rename from packages/core/src/contexts/AppFactoryContext.ts rename to packages/asset-vfs/src/app-factory/AppFactoryContext.ts index cdfe9bf..1c1f680 100644 --- a/packages/core/src/contexts/AppFactoryContext.ts +++ b/packages/asset-vfs/src/app-factory/AppFactoryContext.ts @@ -1,6 +1,6 @@ import { createContext, memo, useContext } from 'react' -import { AssetVFS } from '@modou/asset-vfs' +import { WidgetGroupEnum } from '@modou/core/src/types' import { BranchNode, LoopNode, @@ -38,8 +38,8 @@ import { tableWidgetMetadata, } from '@modou/widgets-antd' -import { AppFactory } from '../app-factory' -import { WidgetGroupEnum } from '../types' +import { AssetVFS } from '../AssetVFS' +import { AppFactory } from './index' export const defaultAppFactory = AppFactory.create({ widgets: [ diff --git a/packages/core/src/app-factory/index.ts b/packages/asset-vfs/src/app-factory/index.ts similarity index 93% rename from packages/core/src/app-factory/index.ts rename to packages/asset-vfs/src/app-factory/index.ts index e90fc79..42d8f84 100644 --- a/packages/core/src/app-factory/index.ts +++ b/packages/asset-vfs/src/app-factory/index.ts @@ -1,13 +1,15 @@ import { isEqual, unionWith } from 'lodash' import { FC } from 'react' +import { + FlowNodeInterpreter, + FlowNodeMetadata, +} from '@modou/core/src/flow-node' +import { WidgetGroupEnum } from '@modou/core/src/types' +import { WidgetMetadata } from '@modou/core/src/widget' import { mrToJsonSchema, schemeToDefs } from '@modou/refine' import { BaseSetterProps } from '@modou/setters/src/types' -import { FlowNodeInterpreter, FlowNodeMetadata } from '../flow-node' -import { WidgetGroupEnum } from '../types' -import { WidgetMetadata } from '../widget' - interface Widget { // FIXME 完善WidgetBaseState定义 component: FC diff --git a/packages/asset-vfs/src/index.ts b/packages/asset-vfs/src/index.ts index 36b1311..b563652 100644 --- a/packages/asset-vfs/src/index.ts +++ b/packages/asset-vfs/src/index.ts @@ -1,20 +1,11 @@ // TODO 优化 asset vfs -import { AppFactory } from '@modou/core' -import { makeAutoObservable } from '@modou/reactivity' // TODO 解决 不同 window 环境下使用不同React的问题 -export class AssetVFS { - constructor({ appFactory }: { appFactory: AppFactory }) { - this.appFactory = appFactory - if (AssetVFS.instance) { - return AssetVFS.instance - } else { - makeAutoObservable(this) - AssetVFS.instance = this - } - } - appFactory: AppFactory - - private static instance: AssetVFS -} +export { AssetVFS } from './AssetVFS' +export { AppFactory } from './app-factory' +export { + AppFactoryContext, + useAppFactory, + defaultAppFactory, +} from './app-factory/AppFactoryContext' diff --git a/packages/canvas-designer/src/components/CanvasDesignerCanvas.tsx b/packages/canvas-designer/src/components/CanvasDesignerCanvas.tsx index 2c8b7fa..378de98 100644 --- a/packages/canvas-designer/src/components/CanvasDesignerCanvas.tsx +++ b/packages/canvas-designer/src/components/CanvasDesignerCanvas.tsx @@ -10,8 +10,8 @@ import { useState, } from 'react' -import { useAppManager } from '@modou/core' import { mcss } from '@modou/css-in-js' +import { useAppManager } from '@modou/meta-vfs' import { observer } from '@modou/reactivity-react' import { useAppState, useCanvasState } from '@modou/state-manager' diff --git a/packages/canvas-designer/src/components/CanvasDesignerPropsPanel.tsx b/packages/canvas-designer/src/components/CanvasDesignerPropsPanel.tsx index 283fffd..338a274 100644 --- a/packages/canvas-designer/src/components/CanvasDesignerPropsPanel.tsx +++ b/packages/canvas-designer/src/components/CanvasDesignerPropsPanel.tsx @@ -9,7 +9,7 @@ import { useState, } from 'react' -import { AppFactoryContext } from '@modou/core' +import { AppFactoryContext } from '@modou/asset-vfs' import { cx, mcss } from '@modou/css-in-js' import { toJS } from '@modou/reactivity' import { observer } from '@modou/reactivity-react' diff --git a/packages/canvas-designer/src/components/CanvasDesignerWidgetStencil.tsx b/packages/canvas-designer/src/components/CanvasDesignerWidgetStencil.tsx index 5acb653..cad8bbe 100644 --- a/packages/canvas-designer/src/components/CanvasDesignerWidgetStencil.tsx +++ b/packages/canvas-designer/src/components/CanvasDesignerWidgetStencil.tsx @@ -3,16 +3,15 @@ import { isEmpty } from 'lodash' import { FC, useContext, useEffect, useMemo, useRef } from 'react' import { useDrag } from 'react-dnd' +import { AppFactory, AppFactoryContext } from '@modou/asset-vfs' import { - AppFactory, - AppFactoryContext, WidgetBaseProps, WidgetGroupEnum, WidgetMetadata, - generateId, getWidgetGroupLabel, } from '@modou/core' import { mcss } from '@modou/css-in-js' +import { generateId } from '@modou/shared' import { WidgetDragType } from '../types' diff --git a/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/DropIndicator.tsx b/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/DropIndicator.tsx index 604f70a..f3728b7 100644 --- a/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/DropIndicator.tsx +++ b/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/DropIndicator.tsx @@ -14,7 +14,8 @@ import { useState, } from 'react' -import { AppFactoryContext, useWidgetMetaSlots } from '@modou/core' +import { AppFactoryContext } from '@modou/asset-vfs' +import { useWidgetMetaSlots } from '@modou/core' import { mcss, useTheme } from '@modou/css-in-js' import { observer } from '@modou/reactivity-react' diff --git a/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/SelectedIndicator.tsx b/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/SelectedIndicator.tsx index 769b751..a34047f 100644 --- a/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/SelectedIndicator.tsx +++ b/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/SelectedIndicator.tsx @@ -9,8 +9,8 @@ import { } from 'react' import { useDrag } from 'react-dnd' -import { useAppManager } from '@modou/core' import { mcss, useTheme } from '@modou/css-in-js' +import { useAppManager } from '@modou/meta-vfs' import { observer } from '@modou/reactivity-react' import { SimulatorInstanceContext } from '../../../contexts' diff --git a/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/SelectedToolBox.tsx b/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/SelectedToolBox.tsx index 0b9f79b..44b5211 100644 --- a/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/SelectedToolBox.tsx +++ b/packages/canvas-designer/src/components/DesignerIndicator/indicatoir/SelectedToolBox.tsx @@ -3,8 +3,8 @@ import { Button } from 'antd' import { FC, useContext, useEffect, useRef } from 'react' import { useDrag } from 'react-dnd' -import { useAppManager } from '@modou/core' import { mcss, useTheme } from '@modou/css-in-js' +import { useAppManager } from '@modou/meta-vfs' import { observer } from '@modou/reactivity-react' import { SimulatorInstanceContext } from '../../../contexts' diff --git a/packages/canvas-designer/src/hooks/usePageOutlineTree.tsx b/packages/canvas-designer/src/hooks/usePageOutlineTree.tsx index f870cef..a1f9234 100644 --- a/packages/canvas-designer/src/hooks/usePageOutlineTree.tsx +++ b/packages/canvas-designer/src/hooks/usePageOutlineTree.tsx @@ -2,13 +2,9 @@ import { head, isEmpty } from 'lodash' import { DataNode } from 'rc-tree/es/interface' import { useContext } from 'react' -import { - AppFactoryContext, - WidgetBaseProps, - WidgetSlot, - useAppManager, -} from '@modou/core' -import { PageFile } from '@modou/meta-vfs' +import { AppFactoryContext } from '@modou/asset-vfs' +import { WidgetBaseProps, WidgetSlot } from '@modou/core' +import { PageFile, useAppManager } from '@modou/meta-vfs' import { toJS } from '@modou/reactivity' import { useCanvasDesignerFile } from '../contexts/CanvasDesignerFileContext' diff --git a/packages/canvas-designer/src/hooks/useWidgetDrop.ts b/packages/canvas-designer/src/hooks/useWidgetDrop.ts index 2d6ebdb..c67fb11 100644 --- a/packages/canvas-designer/src/hooks/useWidgetDrop.ts +++ b/packages/canvas-designer/src/hooks/useWidgetDrop.ts @@ -4,7 +4,7 @@ import { useContext, useEffect, useRef } from 'react' import { useDrop } from 'react-dnd' import { match } from 'ts-pattern' -import { AppFactoryContext } from '@modou/core' +import { AppFactoryContext } from '@modou/asset-vfs' import { WidgetFileMeta } from '@modou/meta-vfs' import { useCanvasDesignerFile } from '../contexts/CanvasDesignerFileContext' diff --git a/packages/core/package.json b/packages/core/package.json index 551302e..66a2259 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -10,6 +10,5 @@ "author": "", "license": "ISC", "dependencies": { - "nanoid": "^4.0.0" } } diff --git a/packages/core/src/contexts/WidgetsDeepPositionContext.ts b/packages/core/src/contexts/WidgetsDeepPositionContext.ts deleted file mode 100644 index e69de29..0000000 diff --git a/packages/core/src/contexts/index.ts b/packages/core/src/contexts/index.ts deleted file mode 100644 index 83c0d52..0000000 --- a/packages/core/src/contexts/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './AppFactoryContext' -export * from './AppManagerContext' diff --git a/packages/core/src/flow-node/FlowNodeMetadata.ts b/packages/core/src/flow-node/FlowNodeMetadata.ts index 4595548..5bd121c 100644 --- a/packages/core/src/flow-node/FlowNodeMetadata.ts +++ b/packages/core/src/flow-node/FlowNodeMetadata.ts @@ -17,9 +17,9 @@ import { MRStringSetterType, SETTER_KEY, } from '@modou/setters' +import { generateId } from '@modou/shared' import { MDVersion } from '../types' -import { generateId } from '../utils' import { FlowNodeBaseProps, FlowNodePortNameEnum } from './types' // TODO 合并 Widget 类型定义 diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 196df04..a870f86 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -1,6 +1,4 @@ export * from './widget' export * from './flow-node' -export * from './app-factory' export * from './types' -export * from './contexts' export * from './utils' diff --git a/packages/core/src/utils/index.ts b/packages/core/src/utils/index.ts index 019a5f2..43d0bca 100644 --- a/packages/core/src/utils/index.ts +++ b/packages/core/src/utils/index.ts @@ -1,12 +1,5 @@ -import { customAlphabet } from 'nanoid' - import { WidgetGroupEnum } from '../types' -const nanoid = customAlphabet('abcdefghigklmnopqrstuvwxyz', 12) -export const generateId = (size: number = 12): string => { - return nanoid(size) -} - export const getWidgetGroupLabel = (group: WidgetGroupEnum) => { switch (group) { case WidgetGroupEnum.Button: diff --git a/packages/flow-designer/src/FlowDesigner/components/ContextMenu.tsx b/packages/flow-designer/src/FlowDesigner/components/ContextMenu.tsx new file mode 100644 index 0000000..7f911f6 --- /dev/null +++ b/packages/flow-designer/src/FlowDesigner/components/ContextMenu.tsx @@ -0,0 +1,95 @@ +import { useClickAway } from 'ahooks' +import { Card } from 'antd' +import { FC, useRef } from 'react' +import { useReactFlow } from 'reactflow' + +import { useAppFactory } from '@modou/asset-vfs' +import { FlowNodeMetadata } from '@modou/core' +import { mcss } from '@modou/css-in-js' +import { FlowNodeEnum } from '@modou/flow-nodes' +import { FlowFile } from '@modou/meta-vfs/src/FlowFile' +import { FlowNodeFile } from '@modou/meta-vfs/src/FlowNodeFile' +import { generateId } from '@modou/shared' + +export const ContextMenu: FC<{ + position: { x: number; y: number } + open: boolean + setOpen: (open: boolean) => void + file: FlowFile +}> = ({ position, open, file, setOpen }) => { + const { appFactory } = useAppFactory() + + const { project } = useReactFlow() + + const flowNodes = Object.values(appFactory.flowNodeByType).filter( + (node) => + ![FlowNodeEnum.START_NODE].includes( + node.metadata.type as unknown as FlowNodeEnum, + ), + ) + + const wrapperRef = useRef(null) + + useClickAway(() => { + setOpen(false) + }, wrapperRef) + + return open ? ( + + {flowNodes.map((node) => ( +
{ + console.log('position', position) + FlowNodeFile.create( + { + ...FlowNodeMetadata.mrSchemeToDefaultJson( + appFactory.flowNodeByType[node.metadata.type].metadata + .jsonPropsSchema, + ), + id: generateId(), + position: project({ + x: position.x, + y: position.y, + }), + }, + file, + ) + setOpen(false) + }} + > + {node.metadata.name} +
+ ))} +
+ ) : null +} + +const classes = { + wrapper: mcss` + position: absolute; + left: 0; + top: 0; + z-index: 999999; + .ant-card-body{ + padding: 0; + } + `, + node: mcss` + font-size: 12px; + padding: 4px 16px; + cursor: default; + &+&{ + border-top: 1px solid rgba(0,0,0,.1); + } + `, +} diff --git a/packages/flow-designer/src/FlowDesigner/index.tsx b/packages/flow-designer/src/FlowDesigner/index.tsx index 3d007c1..824f282 100644 --- a/packages/flow-designer/src/FlowDesigner/index.tsx +++ b/packages/flow-designer/src/FlowDesigner/index.tsx @@ -1,16 +1,15 @@ -import { useClickAway } from 'ahooks' import { mapValues } from 'lodash' -import { FC, useMemo, useRef, useState } from 'react' -import ReactFlow, { Controls } from 'reactflow' +import { ComponentProps, FC, useMemo, useState } from 'react' +import ReactFlow, { Controls, ReactFlowProvider } from 'reactflow' -import { FlowNodeMetadata, generateId, useAppFactory } from '@modou/core' +import { useAppFactory } from '@modou/asset-vfs' import { mcss } from '@modou/css-in-js' -import { FlowNodeEnum } from '@modou/flow-nodes' import { FlowFile } from '@modou/meta-vfs/src/FlowFile' -import { FlowNodeFile } from '@modou/meta-vfs/src/FlowNodeFile' import { observer } from '@modou/reactivity-react' +import { getMonitorWall } from '@modou/shared' import { TurboEdge, TurboNode } from './components' +import { ContextMenu } from './components/ContextMenu' const NODE_TYPES = { turbo: TurboNode, @@ -27,7 +26,6 @@ const defaultEdgeOptions = { export const UOFlowDesigner: FC<{ file: FlowFile }> = ({ file }) => { const { appFactory } = useAppFactory() - const contextMenuRef = useRef(null) const [contextMenuOpen, setContextMenuOpen] = useState(false) const [contextMenuPosition, setContextMenuPosition] = useState({ x: 0, y: 0 }) @@ -38,96 +36,95 @@ export const UOFlowDesigner: FC<{ file: FlowFile }> = ({ file }) => { } }, []) - useClickAway(() => { - setContextMenuOpen(false) - }, contextMenuRef) - return ( - <> - {contextMenuOpen && ( -
{ - FlowNodeFile.create( - { - ...FlowNodeMetadata.mrSchemeToDefaultJson( - appFactory.flowNodeByType[FlowNodeEnum.BRANCH_NODE].metadata - .jsonPropsSchema, - ), - id: generateId(), - position: { - x: contextMenuPosition.x, - y: contextMenuPosition.y, - }, - }, - file, - ) +
+ <> + + { + const target = e.target as unknown as HTMLDivElement + if (!target.classList.contains('react-flow__pane')) { + return + } + + const { left, top } = getMonitorWall(target) + + setContextMenuPosition({ + x: e.clientX - left, + y: e.clientY - top, + }) + setContextMenuOpen(true) + e.preventDefault() }} > - 123 -
- )} - { - setContextMenuPosition({ - x: e.clientX, - y: e.clientY, - }) - setContextMenuOpen(true) - e.preventDefault() - }} - > - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + +
) } -export const FlowDesigner = observer(UOFlowDesigner) +const _FlowDesigner = observer(UOFlowDesigner) + +export const FlowDesigner: FC> = ( + props, +) => { + return ( + + <_FlowDesigner {...props} /> + + ) +} export const classes = { + wrapper: mcss` + position: relative; + height: 100%; + `, reactFlow: mcss` //--bg-color: rgb(17, 17, 17); --bg-color: rgb(255,255,255); @@ -293,14 +290,4 @@ export const classes = { color: #95679e; } `, - contextMenuWrapper: mcss` - position: fixed; - width: 100px; - height: 200px; - left: 0; - top: 0; - z-index: 999999; - color: white; - border: 1px solid red; - `, } diff --git a/packages/flow-nodes/src/BranchNode/index.tsx b/packages/flow-nodes/src/BranchNode/index.tsx index 0fc4b9c..b07579f 100644 --- a/packages/flow-nodes/src/BranchNode/index.tsx +++ b/packages/flow-nodes/src/BranchNode/index.tsx @@ -2,7 +2,6 @@ import { Button, Space } from 'antd' import { type FC } from 'react' import { NodeProps } from 'reactflow' -import { generateId } from '@modou/core' import { FlowNodeFile, FlowNodeFileMeta, @@ -10,6 +9,7 @@ import { import { runInAction } from '@modou/reactivity' import { observer } from '@modou/reactivity-react' import { mr } from '@modou/refine' +import { generateId } from '@modou/shared' import { FlowNodeHandles } from '../_/components/FlowNodeHandles' import { FlowNodeWrapper } from '../_/components/FlowNodeWrapper' @@ -17,7 +17,7 @@ import { CaseBlock } from './CaseBlock' import { DEFAULT_LASE_ELSE_SCRIPT } from './constants' import { MRSchemeBranchNodeProps, branchNodeNodeMetadata } from './metadata' -const _BranchNode: FC< +const UOBranchNode: FC< NodeProps< FlowNodeFile>> > @@ -47,7 +47,6 @@ const _BranchNode: FC< }) }} onDeleteBranch={(branch) => { - // TODO 删除 branch 的同时删除相关的边 runInAction(() => { props.data.meta.props.branches = props.data.meta.props.branches @@ -107,4 +106,4 @@ const _BranchNode: FC< ) } -export const BranchNode = observer(_BranchNode) +export const BranchNode = observer(UOBranchNode) diff --git a/packages/flow-nodes/src/BranchNode/interpreter.ts b/packages/flow-nodes/src/BranchNode/interpreter.ts index 236d053..4051088 100644 --- a/packages/flow-nodes/src/BranchNode/interpreter.ts +++ b/packages/flow-nodes/src/BranchNode/interpreter.ts @@ -1,4 +1,4 @@ -import { FlowNodeInterpreter } from '@modou/core' +import { type FlowNodeInterpreter } from '@modou/core' import { evalScript } from '@modou/evaluate' import { MRSchemeBranchNodeProps } from '@modou/flow-nodes' import { mr } from '@modou/refine' diff --git a/packages/flow-nodes/src/LoopNode/index.tsx b/packages/flow-nodes/src/LoopNode/index.tsx index 5e69abc..609f0b0 100644 --- a/packages/flow-nodes/src/LoopNode/index.tsx +++ b/packages/flow-nodes/src/LoopNode/index.tsx @@ -16,7 +16,7 @@ import { nodeClasses } from '../_/styles' import { ScopedFlowNodePortNameEnum } from '../_/types' import { MRSchemeLoopNodeProps, loopNodeMetadata } from './metadata' -const _LoopNode: FC< +const UOLoopNode: FC< NodeProps< FlowNodeFile>> > @@ -58,4 +58,4 @@ const _LoopNode: FC< ) } -export const LoopNode = observer(_LoopNode) +export const LoopNode = observer(UOLoopNode) diff --git a/packages/flow-nodes/src/RunScriptNode/index.tsx b/packages/flow-nodes/src/RunScriptNode/index.tsx index 9b2db4f..1a14805 100644 --- a/packages/flow-nodes/src/RunScriptNode/index.tsx +++ b/packages/flow-nodes/src/RunScriptNode/index.tsx @@ -14,7 +14,7 @@ import { FlowNodeHandles } from '../_/components/FlowNodeHandles' import { FlowNodeWrapper } from '../_/components/FlowNodeWrapper' import { MRSchemeRunScriptNodeProps, runScriptNodeMetadata } from './metadata' -const _RunScriptNode: FC< +const UORunScriptNode: FC< NodeProps< FlowNodeFile>> > @@ -42,4 +42,4 @@ const _RunScriptNode: FC< ) } -export const RunScriptNode = observer(_RunScriptNode) +export const RunScriptNode = observer(UORunScriptNode) diff --git a/packages/flow-nodes/src/StartNode/index.tsx b/packages/flow-nodes/src/StartNode/index.tsx index f87244a..4f33672 100644 --- a/packages/flow-nodes/src/StartNode/index.tsx +++ b/packages/flow-nodes/src/StartNode/index.tsx @@ -8,7 +8,7 @@ import { FlowNodeHandles } from '../_/components/FlowNodeHandles' import { FlowNodeWrapper } from '../_/components/FlowNodeWrapper' import { startNodeMetadata } from './metadata' -const _StartNode: FC> = (props) => { +const UOStartNode: FC> = (props) => { return ( <> @@ -20,6 +20,6 @@ const _StartNode: FC> = (props) => { ) } -export const StartNode = observer(_StartNode) +export const StartNode = observer(UOStartNode) // const classes = {} diff --git a/packages/flow-nodes/src/_/components/FlowNodeWrapper.tsx b/packages/flow-nodes/src/_/components/FlowNodeWrapper.tsx index 7e84092..24d76ca 100644 --- a/packages/flow-nodes/src/_/components/FlowNodeWrapper.tsx +++ b/packages/flow-nodes/src/_/components/FlowNodeWrapper.tsx @@ -1,4 +1,5 @@ -import { Input } from 'antd' +import { DeleteOutlined } from '@ant-design/icons' +import { Button, Input } from 'antd' import { FC, ReactNode, useState } from 'react' import { NodeProps } from 'reactflow' @@ -51,8 +52,19 @@ const UOFlowNodeWrapper: FC<{ /> )}
+ {meta.name} +
+ +
+
- {meta.name}
{children &&
{children}
}
@@ -66,16 +78,17 @@ const classes = { border: 1px solid #1677ff; border-radius: 8px; //height: 40px; - width: 360px; + width: 220px; //overflow: hidden; - font-size: 14px; + font-size: 12px; box-sizing: border-box; `, header: mcss` background-color: #888888; - height: 34px; + height: 28px; display: flex; align-items: center; + justify-content: space-between; padding: 0 8px; color: white; border-top-left-radius: 8px; @@ -87,11 +100,12 @@ const classes = { headerLeft: mcss` display: flex; align-items: center; - border-right: 1px solid white; - margin-right: 4px; + `, nameWrapper: mcss` padding: 0 4px; + border-right: 1px solid white; + margin-right: 4px; `, readOnlyName: mcss` &:hover{ diff --git a/packages/core/src/contexts/AppManagerContext.tsx b/packages/meta-vfs/src/AppManagerContext.tsx similarity index 89% rename from packages/core/src/contexts/AppManagerContext.tsx rename to packages/meta-vfs/src/AppManagerContext.tsx index 764495a..42404c5 100644 --- a/packages/core/src/contexts/AppManagerContext.tsx +++ b/packages/meta-vfs/src/AppManagerContext.tsx @@ -1,6 +1,6 @@ import { FC, ReactNode, createContext, useContext } from 'react' -import { AppManager } from '@modou/meta-vfs/src/AppManager' +import { AppManager } from './AppManager' const AppManagerContext = createContext(null) diff --git a/packages/meta-vfs/src/FlowFile/index.ts b/packages/meta-vfs/src/FlowFile/index.ts index 7948ed7..422f82b 100644 --- a/packages/meta-vfs/src/FlowFile/index.ts +++ b/packages/meta-vfs/src/FlowFile/index.ts @@ -11,6 +11,7 @@ import { import { FileTypeEnum, PageFile } from '@modou/meta-vfs' import { + action, computed, makeObservable, observable, @@ -38,6 +39,8 @@ export class FlowFile extends BaseFile { flowNodes: computed, flowEdges: computed, reactFlowNodes: computed.struct, + deleteNode: action, + deleteEdge: action, }) } @@ -70,7 +73,6 @@ export class FlowFile extends BaseFile { } get reactFlowEdges() { - console.log('this.flowEdges', this.flowEdges) return this.flowEdges.map((e) => e.reactFlowMeta) } @@ -98,6 +100,27 @@ export class FlowFile extends BaseFile { }) } + deleteNode(nodeId: string) { + const edges = this.subFileMap.flowEdges.filter( + (edge) => edge.meta.target !== nodeId && edge.meta.source !== nodeId, + ) + this.subFileMap.flowEdges.length = 0 + this.subFileMap.flowEdges.push(...edges) + const nodes = this.subFileMap.flowNodes.filter( + (node) => node.meta.id !== nodeId, + ) + this.subFileMap.flowNodes.length = 0 + this.subFileMap.flowNodes.push(...nodes) + } + + deleteEdge(edgeId: string) { + const edges = this.subFileMap.flowEdges.filter( + (edge) => edge.meta.id !== edgeId, + ) + this.subFileMap.flowEdges.length = 0 + this.subFileMap.flowEdges.push(...edges) + } + onReactFlowEdgesChange = (changes: EdgeChange[]) => { const edges = applyEdgeChanges(changes, this.reactFlowEdges) this.updateReactFlowEdges(edges) diff --git a/packages/meta-vfs/src/index.ts b/packages/meta-vfs/src/index.ts index 9b0f807..86c7a5b 100644 --- a/packages/meta-vfs/src/index.ts +++ b/packages/meta-vfs/src/index.ts @@ -17,6 +17,8 @@ export * from './WidgetFile' export * from './types' // export * from './AppManager' + +export * from './AppManagerContext' // export class AppManager { // constructor(app: AppFile) { // this.app = app diff --git a/packages/render/src/components/ReactRender.tsx b/packages/render/src/components/ReactRender.tsx index 44ee62a..fe18dcf 100644 --- a/packages/render/src/components/ReactRender.tsx +++ b/packages/render/src/components/ReactRender.tsx @@ -4,7 +4,8 @@ import zhCN from 'antd/locale/zh_CN' import { FC, useContext } from 'react' import * as React from 'react' -import { AppFactoryContext, AppManagerProvider } from '@modou/core' +import { AppFactoryContext } from '@modou/asset-vfs' +import { AppManagerProvider } from '@modou/meta-vfs' import { observer } from '@modou/reactivity-react' import { AppStateProvider, CanvasStateProvider } from '@modou/state-manager' diff --git a/packages/render/src/components/ReactRenderTolerant.tsx b/packages/render/src/components/ReactRenderTolerant.tsx index 2c54a98..ab3eefe 100644 --- a/packages/render/src/components/ReactRenderTolerant.tsx +++ b/packages/render/src/components/ReactRenderTolerant.tsx @@ -2,8 +2,8 @@ import { Spin } from 'antd' import { FC } from 'react' import * as React from 'react' -import { useAppManager } from '@modou/core' import { mcss } from '@modou/css-in-js' +import { useAppManager } from '@modou/meta-vfs' import { observer } from '@modou/reactivity-react' import { DEFAULT_WIDGET_VARIABLES, diff --git a/packages/render/src/components/WidgetVirtual.tsx b/packages/render/src/components/WidgetVirtual.tsx index 0664761..eb46af2 100644 --- a/packages/render/src/components/WidgetVirtual.tsx +++ b/packages/render/src/components/WidgetVirtual.tsx @@ -1,7 +1,8 @@ import { FC, useContext, useEffect, useState } from 'react' import * as React from 'react' -import { AppFactoryContext, useAppManager } from '@modou/core' +import { AppFactoryContext } from '@modou/asset-vfs' +import { useAppManager } from '@modou/meta-vfs' import { toJS } from '@modou/reactivity' import { observer, useLocalObservable } from '@modou/reactivity-react' import { diff --git a/packages/shared/package.json b/packages/shared/package.json new file mode 100644 index 0000000..9e7bec9 --- /dev/null +++ b/packages/shared/package.json @@ -0,0 +1,15 @@ +{ + "name": "@modou/shared", + "version": "1.0.0", + "description": "", + "main": "src", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "nanoid": "^4.0.1" + } +} diff --git a/packages/shared/src/dom/index.ts b/packages/shared/src/dom/index.ts new file mode 100644 index 0000000..3c68e12 --- /dev/null +++ b/packages/shared/src/dom/index.ts @@ -0,0 +1,15 @@ +// 获取DOM到窗口 X Y 轴距离 +export const getMonitorWall = (element: HTMLElement) => { + let ele: HTMLElement | null = element + let left = ele.offsetLeft + let top = ele.offsetTop + while (ele.offsetParent !== null) { + ele = ele.offsetParent as unknown as HTMLElement + left += ele.offsetLeft + top += ele.offsetTop + } + return { + left, + top, + } +} diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts new file mode 100644 index 0000000..3a3c15a --- /dev/null +++ b/packages/shared/src/index.ts @@ -0,0 +1,8 @@ +import { customAlphabet } from 'nanoid' + +export * from './dom' + +const nanoid = customAlphabet('abcdefghigklmnopqrstuvwxyz', 12) +export const generateId = (size: number = 12): string => { + return nanoid(size) +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0c914e6..d864b05 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -25,6 +25,7 @@ importers: '@modou/refine': workspace:^1.0.0 '@modou/render': workspace:^1.0.0 '@modou/setters': workspace:^1.0.0 + '@modou/shared': workspace:^1.0.0 '@modou/simulator': workspace:^1.0.0 '@modou/state-manager': workspace:^0.0.1 '@modou/widgets-antd': workspace:^1.0.0 @@ -89,6 +90,7 @@ importers: '@modou/refine': link:packages/refine '@modou/render': link:packages/render '@modou/setters': link:packages/setters + '@modou/shared': link:packages/shared '@modou/simulator': link:packages/simulator '@modou/state-manager': link:packages/state-manager '@modou/widgets-antd': link:widgets/antd @@ -421,6 +423,12 @@ importers: packages/setters: specifiers: {} + packages/shared: + specifiers: + nanoid: ^4.0.1 + dependencies: + nanoid: 4.0.1 + packages/simulator: specifiers: {} @@ -11452,6 +11460,12 @@ packages: hasBin: true dev: false + /nanoid/4.0.1: + resolution: {integrity: sha512-udKGtCCUafD3nQtJg9wBhRP3KMbPglUsgV5JVsXhvyBs/oefqb4sqMEhKBBgqZncYowu58p1prsZQBYvAj/Gww==} + engines: {node: ^14 || ^16 || >=18} + hasBin: true + dev: false + /natural-compare/1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true diff --git a/websites/workspace/src/components/CanvasFlow/FlowList.tsx b/websites/workspace/src/components/CanvasFlow/FlowList.tsx index 3364feb..60e3b44 100644 --- a/websites/workspace/src/components/CanvasFlow/FlowList.tsx +++ b/websites/workspace/src/components/CanvasFlow/FlowList.tsx @@ -4,17 +4,15 @@ import { Button, Dropdown, Form, List, Typography } from 'antd' import { ComponentProps, Dispatch, FC, SetStateAction, useContext } from 'react' import { useParams } from 'react-router-dom' -import { - AppFactoryContext, - FlowNodeMetadata, - generateId, - useAppManager, -} from '@modou/core' +import { AppFactoryContext } from '@modou/asset-vfs' +import { FlowNodeMetadata } from '@modou/core' import { mcss } from '@modou/css-in-js' import { FlowNodeEnum } from '@modou/flow-nodes' +import { useAppManager } from '@modou/meta-vfs' import { FlowFile, FlowFileMeta } from '@modou/meta-vfs/src/FlowFile' import { FlowNodeFile } from '@modou/meta-vfs/src/FlowNodeFile' import { Observer, observer } from '@modou/reactivity-react' +import { generateId } from '@modou/shared' import { PageRouterParamsKey } from '../../types' diff --git a/websites/workspace/src/features/app/components/AppHome.tsx b/websites/workspace/src/features/app/components/AppHome.tsx index b15e39b..bb83401 100644 --- a/websites/workspace/src/features/app/components/AppHome.tsx +++ b/websites/workspace/src/features/app/components/AppHome.tsx @@ -6,8 +6,8 @@ import { head, isEmpty } from 'lodash' import { FC, useEffect } from 'react' import { useNavigate, useParams } from 'react-router-dom' -import { useAppManager } from '@modou/core' import { mcss } from '@modou/css-in-js' +import { useAppManager } from '@modou/meta-vfs' import { observer } from '@modou/reactivity-react' const _AppHome: FC = () => { diff --git a/websites/workspace/src/features/app/components/ModuleManagerPage.tsx b/websites/workspace/src/features/app/components/ModuleManagerPage.tsx index cc9e39f..069f22b 100644 --- a/websites/workspace/src/features/app/components/ModuleManagerPage.tsx +++ b/websites/workspace/src/features/app/components/ModuleManagerPage.tsx @@ -8,10 +8,16 @@ import { ComponentProps, FC } from 'react' import { createPortal } from 'react-dom' import { useNavigate, useParams } from 'react-router-dom' -import { WidgetMetadata, generateId, useAppManager } from '@modou/core' +import { WidgetMetadata } from '@modou/core' import { mcss } from '@modou/css-in-js' -import { PageFile, PageFileMeta, WidgetFile } from '@modou/meta-vfs' +import { + PageFile, + PageFileMeta, + WidgetFile, + useAppManager, +} from '@modou/meta-vfs' import { Observer, observer } from '@modou/reactivity-react' +import { generateId } from '@modou/shared' import { rowWidgetMetadata } from '@modou/widgets-antd' enum PageActionEnum { diff --git a/websites/workspace/src/features/app/routers/App.tsx b/websites/workspace/src/features/app/routers/App.tsx index 2988723..7eed949 100644 --- a/websites/workspace/src/features/app/routers/App.tsx +++ b/websites/workspace/src/features/app/routers/App.tsx @@ -13,9 +13,8 @@ import { useParams, } from 'react-router-dom' -import { AppManagerProvider } from '@modou/core' import { mcss } from '@modou/css-in-js' -import { AppFile, AppManager } from '@modou/meta-vfs' +import { AppFile, AppManager, AppManagerProvider } from '@modou/meta-vfs' import { runInAction } from '@modou/reactivity' import { AppState, AppStateProvider } from '@modou/state-manager' diff --git a/websites/workspace/src/features/app/routers/mock.ts b/websites/workspace/src/features/app/routers/mock.ts index e885802..abc9e96 100644 --- a/websites/workspace/src/features/app/routers/mock.ts +++ b/websites/workspace/src/features/app/routers/mock.ts @@ -1,4 +1,4 @@ -import { WidgetBaseProps, WidgetMetadata, generateId } from '@modou/core' +import { WidgetBaseProps, WidgetMetadata } from '@modou/core' import { AppFile, EntityFieldEnum, @@ -11,6 +11,7 @@ import { PageFile, WidgetFile, } from '@modou/meta-vfs' +import { generateId } from '@modou/shared' import { buttonWidgetMetadata, colWidgetMetadata, diff --git a/websites/workspace/src/features/entity/components/EntitiesER.tsx b/websites/workspace/src/features/entity/components/EntitiesER.tsx index 7b570d7..ca7848a 100644 --- a/websites/workspace/src/features/entity/components/EntitiesER.tsx +++ b/websites/workspace/src/features/entity/components/EntitiesER.tsx @@ -14,8 +14,8 @@ import ReactFlow, { useNodesState, } from 'reactflow' -import { useAppManager } from '@modou/core' import { mcss, useTheme } from '@modou/css-in-js' +import { useAppManager } from '@modou/meta-vfs' import { runInAction } from '@modou/reactivity' import { observer } from '@modou/reactivity-react' diff --git a/websites/workspace/src/features/entity/components/EntitiesList.tsx b/websites/workspace/src/features/entity/components/EntitiesList.tsx index 4be7c5e..8a1e22a 100644 --- a/websites/workspace/src/features/entity/components/EntitiesList.tsx +++ b/websites/workspace/src/features/entity/components/EntitiesList.tsx @@ -2,9 +2,8 @@ import { Button, Space, Table } from 'antd' import { ColumnsType } from 'antd/es/table' import { FC } from 'react' -import { useAppManager } from '@modou/core' import { mcss } from '@modou/css-in-js' -import { EntityFileMeta } from '@modou/meta-vfs' +import { EntityFileMeta, useAppManager } from '@modou/meta-vfs' import { observer } from '@modou/reactivity-react' const _EntitiesList: FC<{ diff --git a/websites/workspace/src/features/entity/components/EntityFieldCreator.tsx b/websites/workspace/src/features/entity/components/EntityFieldCreator.tsx index 65c0f55..530aa8c 100644 --- a/websites/workspace/src/features/entity/components/EntityFieldCreator.tsx +++ b/websites/workspace/src/features/entity/components/EntityFieldCreator.tsx @@ -15,13 +15,14 @@ import { useState, } from 'react' -import { generateId, useAppManager } from '@modou/core' import { EntityFieldEnum, EntityFieldFile, EntityFieldFileMeta, EntityFile, + useAppManager, } from '@modou/meta-vfs' +import { generateId } from '@modou/shared' const buildEntityFieldConfig = ( entityFieldType: EntityFieldEnum, diff --git a/websites/workspace/src/features/entity/components/EntityFields.tsx b/websites/workspace/src/features/entity/components/EntityFields.tsx index efce5f4..7701250 100644 --- a/websites/workspace/src/features/entity/components/EntityFields.tsx +++ b/websites/workspace/src/features/entity/components/EntityFields.tsx @@ -2,8 +2,7 @@ import { Button, Space, Table } from 'antd' import { ColumnsType } from 'antd/es/table' import { ComponentProps, FC, useRef } from 'react' -import { useAppManager } from '@modou/core' -import { EntityFieldFileMeta } from '@modou/meta-vfs' +import { EntityFieldFileMeta, useAppManager } from '@modou/meta-vfs' import { observer } from '@modou/reactivity-react' import { EntityFieldCreator } from './EntityFieldCreator' diff --git a/websites/workspace/src/features/entity/components/EntityModuleActions.tsx b/websites/workspace/src/features/entity/components/EntityModuleActions.tsx index 011ab56..af98325 100644 --- a/websites/workspace/src/features/entity/components/EntityModuleActions.tsx +++ b/websites/workspace/src/features/entity/components/EntityModuleActions.tsx @@ -2,7 +2,7 @@ import { useMount } from 'ahooks' import { FC, ReactNode, useState } from 'react' import { createPortal } from 'react-dom' -import { generateId } from '@modou/core' +import { generateId } from '@modou/shared' const ENTITY_MODULE_ACTION_PORTAL_ID = generateId() export const EntityModuleActionWrapper: FC<{ children: ReactNode }> = ({ diff --git a/websites/workspace/src/features/entity/hooks/useEntityCreator.ts b/websites/workspace/src/features/entity/hooks/useEntityCreator.ts index 5678496..e96507c 100644 --- a/websites/workspace/src/features/entity/hooks/useEntityCreator.ts +++ b/websites/workspace/src/features/entity/hooks/useEntityCreator.ts @@ -1,8 +1,8 @@ import { useBoolean } from 'ahooks' import { Form } from 'antd' -import { generateId, useAppManager } from '@modou/core' -import { EntityFile, EntityFileMeta } from '@modou/meta-vfs' +import { EntityFile, EntityFileMeta, useAppManager } from '@modou/meta-vfs' +import { generateId } from '@modou/shared' export const useEntityCreator = () => { const [open, { setFalse, setTrue }] = useBoolean(false) diff --git a/websites/workspace/src/features/entity/routers/Entity.tsx b/websites/workspace/src/features/entity/routers/Entity.tsx index ccb06f1..6869914 100644 --- a/websites/workspace/src/features/entity/routers/Entity.tsx +++ b/websites/workspace/src/features/entity/routers/Entity.tsx @@ -4,8 +4,8 @@ import { Card } from 'antd' import { FC } from 'react' import { useParams } from 'react-router-dom' -import { useAppManager } from '@modou/core' import { mcss } from '@modou/css-in-js' +import { useAppManager } from '@modou/meta-vfs' import { observer } from '@modou/reactivity-react' import { diff --git a/websites/workspace/src/features/page/routers/Page.tsx b/websites/workspace/src/features/page/routers/Page.tsx index a6a046a..2dbe0b3 100644 --- a/websites/workspace/src/features/page/routers/Page.tsx +++ b/websites/workspace/src/features/page/routers/Page.tsx @@ -6,13 +6,10 @@ import { head } from 'lodash' import { FC, useLayoutEffect } from 'react' import { useNavigate, useParams } from 'react-router-dom' +import { AppFactoryContext, defaultAppFactory } from '@modou/asset-vfs' import { CanvasDesigner } from '@modou/canvas-designer' -import { - AppFactoryContext, - defaultAppFactory, - useAppManager, -} from '@modou/core' import { mcss } from '@modou/css-in-js' +import { useAppManager } from '@modou/meta-vfs' import { observer } from '@modou/reactivity-react' import { SimulatorPC } from '@modou/simulator' From 579e47081a52dc4d7cb22f35133c0cbe6d781c3b Mon Sep 17 00:00:00 2001 From: liulei Date: Mon, 20 Feb 2023 02:21:41 +0800 Subject: [PATCH 66/68] chore: update antd --- package.json | 4 +- pnpm-lock.yaml | 234 +++++++++++++++++++++++-------------------------- 2 files changed, 111 insertions(+), 127 deletions(-) diff --git a/package.json b/package.json index 1f81c4a..0631ca8 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ }, "dependencies": { "@ant-design/icons": "^5.0.1", - "@ant-design/pro-components": "^2.3.52", + "@ant-design/pro-components": "^2.3.57", "@modou/asset-vfs": "workspace:^1.0.0", "@modou/code-editor": "workspace:^1.0.0", "@modou/compile-core": "workspace:^0.0.1", @@ -60,7 +60,7 @@ "@vue/compiler-core": "^3.2.45", "@vue/runtime-core": "^3.2.45", "ahooks": "^3.7.0", - "antd": "^5.1.7", + "antd": "^5.2.2", "axios": "^1.1.3", "flat": "^5.0.2", "handlebars": "^4.7.7", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d864b05..6578461 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,7 +10,7 @@ importers: .: specifiers: '@ant-design/icons': ^5.0.1 - '@ant-design/pro-components': ^2.3.52 + '@ant-design/pro-components': ^2.3.57 '@emotion/babel-plugin': ^11.10.5 '@modou/asset-vfs': workspace:^1.0.0 '@modou/code-editor': workspace:^1.0.0 @@ -40,7 +40,7 @@ importers: '@vue/compiler-core': ^3.2.45 '@vue/runtime-core': ^3.2.45 ahooks: ^3.7.0 - antd: ^5.1.7 + antd: ^5.2.2 autoprefixer: ^10.4.8 axios: ^1.1.3 commitizen: 4.2.5 @@ -76,7 +76,7 @@ importers: vite: ^4.0.3 dependencies: '@ant-design/icons': 5.0.1_biqbaboplfbrettd7655fr4n2y - '@ant-design/pro-components': 2.3.52_aac2f7bij6zdfxpifyhyipckra + '@ant-design/pro-components': 2.3.57_xan5c2tkf4stwpqcwacropitz4 '@modou/asset-vfs': link:packages/asset-vfs '@modou/code-editor': link:packages/code-editor '@modou/compile-core': link:packages/compiler-core @@ -98,7 +98,7 @@ importers: '@vue/compiler-core': 3.2.45 '@vue/runtime-core': 3.2.45 ahooks: 3.7.1_react@18.2.0 - antd: 5.1.7_biqbaboplfbrettd7655fr4n2y + antd: 5.2.2_biqbaboplfbrettd7655fr4n2y axios: 1.1.3 flat: 5.0.2 handlebars: 4.7.7 @@ -225,10 +225,7 @@ importers: stylelint: 14.16.1 packages/core: - specifiers: - nanoid: ^4.0.0 - dependencies: - nanoid: 4.0.0 + specifiers: {} packages/css-in-js: specifiers: @@ -491,13 +488,13 @@ packages: /@ant-design/colors/6.0.0: resolution: {integrity: sha512-qAZRvPzfdWHtfameEGP2Qvuf838NhergR35o+EuVyB5XvSA98xod5r4utvi4TJ3ywmevm290g9nsCG5MryrdWQ==} dependencies: - '@ctrl/tinycolor': 3.4.1 + '@ctrl/tinycolor': 3.6.0 dev: false /@ant-design/colors/7.0.0: resolution: {integrity: sha512-iVm/9PfGCbC0dSMBrz7oiEXZaaGH7ceU40OJEfKmyuzR9R5CRimJYPlRiFtMQGQcbNMea/ePcoIebi4ASGYXtg==} dependencies: - '@ctrl/tinycolor': 3.4.1 + '@ctrl/tinycolor': 3.6.0 dev: false /@ant-design/cssinjs/1.5.6_biqbaboplfbrettd7655fr4n2y: @@ -552,17 +549,17 @@ packages: react-dom: 18.2.0_react@18.2.0 dev: false - /@ant-design/pro-card/2.1.10_aac2f7bij6zdfxpifyhyipckra: - resolution: {integrity: sha512-edajGd2/35w73tLC7yMZf2/8tWg4Wz9pmN6jQgFo+QIRXoaHd5zpeQaOMxZojeqzCxTH0Qt60YpeLp/S+ahupQ==} + /@ant-design/pro-card/2.1.14_xan5c2tkf4stwpqcwacropitz4: + resolution: {integrity: sha512-zIIxaP3tR8j2I6LyvslJBOUBMqQNar9a1KX/jXkYJVle72wz0l67BCW2NaGg9UwJMsCIkIuf24Dfcpy/YKpc+w==} peerDependencies: antd: '>=4.23.0' react: '>=16.9.0' dependencies: '@ant-design/icons': 4.8.0_biqbaboplfbrettd7655fr4n2y - '@ant-design/pro-provider': 2.4.0_aac2f7bij6zdfxpifyhyipckra - '@ant-design/pro-utils': 2.5.4_aac2f7bij6zdfxpifyhyipckra + '@ant-design/pro-provider': 2.4.3_xan5c2tkf4stwpqcwacropitz4 + '@ant-design/pro-utils': 2.5.8_xan5c2tkf4stwpqcwacropitz4 '@babel/runtime': 7.20.7 - antd: 5.1.7_biqbaboplfbrettd7655fr4n2y + antd: 5.2.2_biqbaboplfbrettd7655fr4n2y classnames: 2.3.2 omit.js: 2.0.2 rc-resize-observer: 1.2.0_biqbaboplfbrettd7655fr4n2y @@ -572,25 +569,25 @@ packages: - react-dom dev: false - /@ant-design/pro-components/2.3.52_aac2f7bij6zdfxpifyhyipckra: - resolution: {integrity: sha512-df51Xi59QRXXIc5uMcO/7/tPjNziGt1w40860yCztFBNCoNc9B+xvDwsuRWgvRL1yqM4SZL1Al7T392CtyESSg==} + /@ant-design/pro-components/2.3.57_xan5c2tkf4stwpqcwacropitz4: + resolution: {integrity: sha512-zXHAToBHjHQLrORO4reqknDcMeM+7Vgtqwb40AS+ZUD8uo3s+l8+YiV+BoxZDMbmxsQ0VzANU3610ZmSqUMkqg==} peerDependencies: antd: '>=4.23.0' react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@ant-design/pro-card': 2.1.10_aac2f7bij6zdfxpifyhyipckra - '@ant-design/pro-descriptions': 2.0.44_aac2f7bij6zdfxpifyhyipckra - '@ant-design/pro-field': 2.2.5_aac2f7bij6zdfxpifyhyipckra - '@ant-design/pro-form': 2.5.4_aac2f7bij6zdfxpifyhyipckra - '@ant-design/pro-layout': 7.6.1_aac2f7bij6zdfxpifyhyipckra - '@ant-design/pro-list': 2.0.45_aac2f7bij6zdfxpifyhyipckra - '@ant-design/pro-provider': 2.4.0_aac2f7bij6zdfxpifyhyipckra - '@ant-design/pro-skeleton': 2.0.7_aac2f7bij6zdfxpifyhyipckra - '@ant-design/pro-table': 3.2.12_aac2f7bij6zdfxpifyhyipckra - '@ant-design/pro-utils': 2.5.4_aac2f7bij6zdfxpifyhyipckra + '@ant-design/pro-card': 2.1.14_xan5c2tkf4stwpqcwacropitz4 + '@ant-design/pro-descriptions': 2.0.48_xan5c2tkf4stwpqcwacropitz4 + '@ant-design/pro-field': 2.2.9_xan5c2tkf4stwpqcwacropitz4 + '@ant-design/pro-form': 2.5.8_xan5c2tkf4stwpqcwacropitz4 + '@ant-design/pro-layout': 7.8.2_xan5c2tkf4stwpqcwacropitz4 + '@ant-design/pro-list': 2.1.1_xan5c2tkf4stwpqcwacropitz4 + '@ant-design/pro-provider': 2.4.3_xan5c2tkf4stwpqcwacropitz4 + '@ant-design/pro-skeleton': 2.0.8_xan5c2tkf4stwpqcwacropitz4 + '@ant-design/pro-table': 3.3.1_xan5c2tkf4stwpqcwacropitz4 + '@ant-design/pro-utils': 2.5.8_xan5c2tkf4stwpqcwacropitz4 '@babel/runtime': 7.20.7 - antd: 5.1.7_biqbaboplfbrettd7655fr4n2y + antd: 5.2.2_biqbaboplfbrettd7655fr4n2y react: 18.2.0 react-dom: 18.2.0_react@18.2.0 transitivePeerDependencies: @@ -598,18 +595,18 @@ packages: - rc-field-form dev: false - /@ant-design/pro-descriptions/2.0.44_aac2f7bij6zdfxpifyhyipckra: - resolution: {integrity: sha512-UEwZbvjOBTxWvPGv8qb3i+Q5czuHFYwRokSgVzVyS2el6xLYr4ZjG0a2CQsjbBnIb0MvZCfnkIn+W0XD/bjS3g==} + /@ant-design/pro-descriptions/2.0.48_xan5c2tkf4stwpqcwacropitz4: + resolution: {integrity: sha512-Y5edlJlnvRWF/8BqIcmJP3xSCvi1UT7uMDjFLdHhcIfWJsBgYfdLq7wupY/pN3rRJ0jCvVJUpVRMotdzAuK8ig==} peerDependencies: antd: '>=4.23.0' react: '>=16.9.0' dependencies: - '@ant-design/pro-field': 2.2.5_aac2f7bij6zdfxpifyhyipckra - '@ant-design/pro-form': 2.5.4_aac2f7bij6zdfxpifyhyipckra - '@ant-design/pro-skeleton': 2.0.7_aac2f7bij6zdfxpifyhyipckra - '@ant-design/pro-utils': 2.5.4_aac2f7bij6zdfxpifyhyipckra + '@ant-design/pro-field': 2.2.9_xan5c2tkf4stwpqcwacropitz4 + '@ant-design/pro-form': 2.5.8_xan5c2tkf4stwpqcwacropitz4 + '@ant-design/pro-skeleton': 2.0.8_xan5c2tkf4stwpqcwacropitz4 + '@ant-design/pro-utils': 2.5.8_xan5c2tkf4stwpqcwacropitz4 '@babel/runtime': 7.20.7 - antd: 5.1.7_biqbaboplfbrettd7655fr4n2y + antd: 5.2.2_biqbaboplfbrettd7655fr4n2y rc-util: 5.27.1_biqbaboplfbrettd7655fr4n2y react: 18.2.0 use-json-comparison: 1.0.6_react@18.2.0 @@ -619,18 +616,18 @@ packages: - react-dom dev: false - /@ant-design/pro-field/2.2.5_aac2f7bij6zdfxpifyhyipckra: - resolution: {integrity: sha512-7Rp0uRhdCUnOFKXkId5wCjjQJBWo0sMhOQs10y40/hNpGpTEpVuEmJo2Jx4Sj2hj/g663WOUSF0YBK7PhFtTFA==} + /@ant-design/pro-field/2.2.9_xan5c2tkf4stwpqcwacropitz4: + resolution: {integrity: sha512-Rl9QcdgbQUOfXmpwI1ln4HqxYI4rxIzcyglAPw9wzAfj3hMPglDDy6VzsaSk/bCWAm49rJcRiwyOIp4vuYXOZg==} peerDependencies: antd: '>=4.23.0' react: '>=16.9.0' dependencies: '@ant-design/icons': 4.8.0_biqbaboplfbrettd7655fr4n2y - '@ant-design/pro-provider': 2.4.0_aac2f7bij6zdfxpifyhyipckra - '@ant-design/pro-utils': 2.5.4_aac2f7bij6zdfxpifyhyipckra + '@ant-design/pro-provider': 2.4.3_xan5c2tkf4stwpqcwacropitz4 + '@ant-design/pro-utils': 2.5.8_xan5c2tkf4stwpqcwacropitz4 '@babel/runtime': 7.20.7 '@chenshuai2144/sketch-color': 1.0.8_react@18.2.0 - antd: 5.1.7_biqbaboplfbrettd7655fr4n2y + antd: 5.2.2_biqbaboplfbrettd7655fr4n2y classnames: 2.3.2 dayjs: 1.11.5 lodash.tonumber: 4.0.3 @@ -642,8 +639,8 @@ packages: - react-dom dev: false - /@ant-design/pro-form/2.5.4_aac2f7bij6zdfxpifyhyipckra: - resolution: {integrity: sha512-Udzs2BLLHK9xhryB0GqE4FvC0KVjiD88z0NqSkJT1AfFMbBn5ERUh2TJ87vfSc8CS4UPGGeU868YzXVMR9AkbA==} + /@ant-design/pro-form/2.5.8_xan5c2tkf4stwpqcwacropitz4: + resolution: {integrity: sha512-iBxb7vWOPjlkpfZjZHKnVlgA1ebE7yjuqkXJSQ9AYW2HB1UfXVYcI7xgrj0nkx6EdtL1sf3Rhl2OwKYpRIB9iQ==} peerDependencies: '@types/lodash.merge': ^4.6.7 antd: '>=4.23.0' @@ -655,12 +652,13 @@ packages: optional: true dependencies: '@ant-design/icons': 4.8.0_biqbaboplfbrettd7655fr4n2y - '@ant-design/pro-field': 2.2.5_aac2f7bij6zdfxpifyhyipckra - '@ant-design/pro-provider': 2.4.0_aac2f7bij6zdfxpifyhyipckra - '@ant-design/pro-utils': 2.5.4_aac2f7bij6zdfxpifyhyipckra + '@ant-design/pro-field': 2.2.9_xan5c2tkf4stwpqcwacropitz4 + '@ant-design/pro-provider': 2.4.3_xan5c2tkf4stwpqcwacropitz4 + '@ant-design/pro-utils': 2.5.8_xan5c2tkf4stwpqcwacropitz4 '@babel/runtime': 7.20.7 + '@chenshuai2144/sketch-color': 1.0.8_react@18.2.0 '@umijs/use-params': 1.0.9_react@18.2.0 - antd: 5.1.7_biqbaboplfbrettd7655fr4n2y + antd: 5.2.2_biqbaboplfbrettd7655fr4n2y classnames: 2.3.2 lodash.merge: 4.6.2 omit.js: 2.0.2 @@ -672,20 +670,20 @@ packages: use-media-antd-query: 1.1.0_react@18.2.0 dev: false - /@ant-design/pro-layout/7.6.1_aac2f7bij6zdfxpifyhyipckra: - resolution: {integrity: sha512-MNmOALRmVbAUbsbJSmUdXyKgvxyTG1pp9YYwway5AqKz28PdfDp6HhqrvCE7zRnxIaJWv9Vb6IZ/XqstI5zDeg==} + /@ant-design/pro-layout/7.8.2_xan5c2tkf4stwpqcwacropitz4: + resolution: {integrity: sha512-SvFNyFCu+Ar6EqVBFAdDKdgHTzJonRFTtf+/opr3zJ46jFFoiuxE5qaJqmtOM+Plrvt272yPWUs/yN6R31t6CA==} peerDependencies: antd: '>=4.23.0' react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: '@ant-design/icons': 4.8.0_biqbaboplfbrettd7655fr4n2y - '@ant-design/pro-provider': 2.4.0_aac2f7bij6zdfxpifyhyipckra - '@ant-design/pro-utils': 2.5.4_aac2f7bij6zdfxpifyhyipckra + '@ant-design/pro-provider': 2.4.3_xan5c2tkf4stwpqcwacropitz4 + '@ant-design/pro-utils': 2.5.8_xan5c2tkf4stwpqcwacropitz4 '@babel/runtime': 7.20.7 '@umijs/route-utils': 4.0.1 '@umijs/use-params': 1.0.9_react@18.2.0 - antd: 5.1.7_biqbaboplfbrettd7655fr4n2y + antd: 5.2.2_biqbaboplfbrettd7655fr4n2y classnames: 2.3.2 lodash.merge: 4.6.2 omit.js: 2.0.2 @@ -695,40 +693,38 @@ packages: react: 18.2.0 react-dom: 18.2.0_react@18.2.0 swr: 2.0.0_react@18.2.0 - unstated-next: 1.1.0 use-json-comparison: 1.0.6_react@18.2.0 use-media-antd-query: 1.1.0_react@18.2.0 warning: 4.0.3 dev: false - /@ant-design/pro-list/2.0.45_aac2f7bij6zdfxpifyhyipckra: - resolution: {integrity: sha512-jGcTqL+ziAKZ71NERmbfFST+BoOIyVy6NQNDvTNa2V/r2ZYR+eLStEcRfTp0MyWaWillXJqBIi3jNhDUIXWVhg==} + /@ant-design/pro-list/2.1.1_xan5c2tkf4stwpqcwacropitz4: + resolution: {integrity: sha512-afOlH+Kms4eZzUvmA38lGsqobg+PXHqZtBducfgAJ+QgLxBu172TLKuG5wioTdMCm2DSxIKQ3+rQn0O9ZBdDqw==} peerDependencies: antd: '>=4.23.0' react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: '@ant-design/icons': 4.8.0_biqbaboplfbrettd7655fr4n2y - '@ant-design/pro-card': 2.1.10_aac2f7bij6zdfxpifyhyipckra - '@ant-design/pro-field': 2.2.5_aac2f7bij6zdfxpifyhyipckra - '@ant-design/pro-table': 3.2.12_aac2f7bij6zdfxpifyhyipckra + '@ant-design/pro-card': 2.1.14_xan5c2tkf4stwpqcwacropitz4 + '@ant-design/pro-field': 2.2.9_xan5c2tkf4stwpqcwacropitz4 + '@ant-design/pro-table': 3.3.1_xan5c2tkf4stwpqcwacropitz4 '@babel/runtime': 7.20.7 - antd: 5.1.7_biqbaboplfbrettd7655fr4n2y + antd: 5.2.2_biqbaboplfbrettd7655fr4n2y classnames: 2.3.2 dayjs: 1.11.5 rc-resize-observer: 1.2.0_biqbaboplfbrettd7655fr4n2y rc-util: 4.21.1 react: 18.2.0 react-dom: 18.2.0_react@18.2.0 - unstated-next: 1.1.0 use-media-antd-query: 1.1.0_react@18.2.0 transitivePeerDependencies: - '@types/lodash.merge' - rc-field-form dev: false - /@ant-design/pro-provider/2.4.0_aac2f7bij6zdfxpifyhyipckra: - resolution: {integrity: sha512-toz3F7moI6o99DCaEJRQv/jYrQXYlxiM3RpTb5L+zXYwc4hFxfv8Jj2Qm6XMX0DRZgCsDt5KK7R+9c9LzoNxbg==} + /@ant-design/pro-provider/2.4.3_xan5c2tkf4stwpqcwacropitz4: + resolution: {integrity: sha512-BefEAY9XUE1U5SxLAzA9se4e2VOykMRDyev+cGzz4bewdon/sbX82dcw300rl1n5IB9r+K3wYCzFXX+KaneFSA==} peerDependencies: antd: '>=4.23.0' react: '>=16.9.0' @@ -736,30 +732,30 @@ packages: dependencies: '@ant-design/cssinjs': 1.5.6_biqbaboplfbrettd7655fr4n2y '@babel/runtime': 7.20.7 - '@ctrl/tinycolor': 3.4.1 - antd: 5.1.7_biqbaboplfbrettd7655fr4n2y + '@ctrl/tinycolor': 3.6.0 + antd: 5.2.2_biqbaboplfbrettd7655fr4n2y rc-util: 5.27.1_biqbaboplfbrettd7655fr4n2y react: 18.2.0 react-dom: 18.2.0_react@18.2.0 swr: 2.0.0_react@18.2.0 dev: false - /@ant-design/pro-skeleton/2.0.7_aac2f7bij6zdfxpifyhyipckra: - resolution: {integrity: sha512-7RoCUVgWDTGrWeNuFlscsxrrXc5jshYXk6gjkQKospR0hQ1AK/aWlkttAAaqDFZlvPxSyLu8w11TmquRuYcNcg==} + /@ant-design/pro-skeleton/2.0.8_xan5c2tkf4stwpqcwacropitz4: + resolution: {integrity: sha512-Rb5Fpd6s1q5EemdO43o4w/Eab7ze6Gd3mOdMPHAp2dK5qm3Wj6Qa6Dr94zcsHom2VaZfaPVTatatHxdR+7byOQ==} peerDependencies: antd: '>=4.23.0' react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: '@babel/runtime': 7.20.7 - antd: 5.1.7_biqbaboplfbrettd7655fr4n2y + antd: 5.2.2_biqbaboplfbrettd7655fr4n2y react: 18.2.0 react-dom: 18.2.0_react@18.2.0 use-media-antd-query: 1.1.0_react@18.2.0 dev: false - /@ant-design/pro-table/3.2.12_aac2f7bij6zdfxpifyhyipckra: - resolution: {integrity: sha512-jhfKBtU5DnOlj0eL/Tz3D5j9DZt6KeWCcaJOA/FDr/ZTj5ROUThhK5DqzeLjR9O/DTBCgiwB8Vpiqt0uWPWlXw==} + /@ant-design/pro-table/3.3.1_xan5c2tkf4stwpqcwacropitz4: + resolution: {integrity: sha512-NQak8whJklHUrJlQMs6z2nQ9qPdrDXEbJWG/btxE6kFcfANydLRCdsHVmJADZ7NWv+ZvnAiXAzaR1pJeuZxu5A==} peerDependencies: antd: '>=4.23.0' rc-field-form: ^1.22.0 @@ -767,13 +763,13 @@ packages: react-dom: '>=16.9.0' dependencies: '@ant-design/icons': 4.8.0_biqbaboplfbrettd7655fr4n2y - '@ant-design/pro-card': 2.1.10_aac2f7bij6zdfxpifyhyipckra - '@ant-design/pro-field': 2.2.5_aac2f7bij6zdfxpifyhyipckra - '@ant-design/pro-form': 2.5.4_aac2f7bij6zdfxpifyhyipckra - '@ant-design/pro-provider': 2.4.0_aac2f7bij6zdfxpifyhyipckra - '@ant-design/pro-utils': 2.5.4_aac2f7bij6zdfxpifyhyipckra + '@ant-design/pro-card': 2.1.14_xan5c2tkf4stwpqcwacropitz4 + '@ant-design/pro-field': 2.2.9_xan5c2tkf4stwpqcwacropitz4 + '@ant-design/pro-form': 2.5.8_xan5c2tkf4stwpqcwacropitz4 + '@ant-design/pro-provider': 2.4.3_xan5c2tkf4stwpqcwacropitz4 + '@ant-design/pro-utils': 2.5.8_xan5c2tkf4stwpqcwacropitz4 '@babel/runtime': 7.20.7 - antd: 5.1.7_biqbaboplfbrettd7655fr4n2y + antd: 5.2.2_biqbaboplfbrettd7655fr4n2y classnames: 2.3.2 dayjs: 1.11.5 omit.js: 2.0.2 @@ -782,23 +778,22 @@ packages: react: 18.2.0 react-dom: 18.2.0_react@18.2.0 react-sortable-hoc: 2.0.0_biqbaboplfbrettd7655fr4n2y - unstated-next: 1.1.0 use-json-comparison: 1.0.6_react@18.2.0 transitivePeerDependencies: - '@types/lodash.merge' dev: false - /@ant-design/pro-utils/2.5.4_aac2f7bij6zdfxpifyhyipckra: - resolution: {integrity: sha512-fwnGRcYQbJwIyTWvioCw443qJ2Jq/TdkR/LFoewJqQK8zeZ7I62pEgLqxK0l0sffZpN1cKAIQfydqvcT3kl+mQ==} + /@ant-design/pro-utils/2.5.8_xan5c2tkf4stwpqcwacropitz4: + resolution: {integrity: sha512-iAiNjKBj8chgDsHIn/d757RFEhRLhBPT4iSH5MI7k+hZTHbEMsjYjNgtR9Du5doIP+ACe62hcuELTr6aXt80nQ==} peerDependencies: antd: '>=4.23.0' react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: '@ant-design/icons': 4.8.0_biqbaboplfbrettd7655fr4n2y - '@ant-design/pro-provider': 2.4.0_aac2f7bij6zdfxpifyhyipckra + '@ant-design/pro-provider': 2.4.3_xan5c2tkf4stwpqcwacropitz4 '@babel/runtime': 7.20.7 - antd: 5.1.7_biqbaboplfbrettd7655fr4n2y + antd: 5.2.2_biqbaboplfbrettd7655fr4n2y classnames: 2.3.2 dayjs: 1.11.5 rc-util: 5.27.1_biqbaboplfbrettd7655fr4n2y @@ -1879,8 +1874,8 @@ packages: postcss-selector-parser: 6.0.11 dev: true - /@ctrl/tinycolor/3.4.1: - resolution: {integrity: sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw==} + /@ctrl/tinycolor/3.6.0: + resolution: {integrity: sha512-/Z3l6pXthq0JvMYdUFyX9j0MaCltlIn6mfh9jLyQwg5aPKxkyNa0PTHtU1AlFXLNk55ZuAeJRcpvq+tmLfKmaQ==} engines: {node: '>=10'} dev: false @@ -2864,8 +2859,8 @@ packages: react-dom: 18.2.0_react@18.2.0 dev: false - /@rc-component/tour/1.1.0_biqbaboplfbrettd7655fr4n2y: - resolution: {integrity: sha512-Cy45VnNEDq6DLF5eKonIflObDfofbPq7AJpSf18qLN+j9+wW+sNlRv3JnCMDUsCdhSlnM4+yJ1RMokKp9GCpOQ==} + /@rc-component/tour/1.6.0_biqbaboplfbrettd7655fr4n2y: + resolution: {integrity: sha512-b/s7LCb7bW4wxpWfZyNpl7khHUzSyObSlsLaIScRGd+W/v1wFVk8F7gRytl/z8ik9ZSXbLWx9EvexIuHoO/RcQ==} engines: {node: '>=8.x'} peerDependencies: react: '>=16.9.0' @@ -5143,8 +5138,8 @@ packages: engines: {node: '>=12'} dev: true - /antd/5.1.7_biqbaboplfbrettd7655fr4n2y: - resolution: {integrity: sha512-rz7wrUPWfE1WAt7o8vlTmjfxVmbV0Vyh00PEO8F837Gq0wugvOiWVPJ4BI/piIxUIpKXASYmCYWOczoHCkwBMQ==} + /antd/5.2.2_biqbaboplfbrettd7655fr4n2y: + resolution: {integrity: sha512-IHuMyGvgI+pPmoZNJFfhVykb0eW6+iO/39/9qPE0ub9gKAnI4vaK+hA5li6aX+mjM/EqgckdWgLpaIP98kGrvw==} peerDependencies: react: '>=16.9.0' react-dom: '>=16.9.0' @@ -5154,24 +5149,24 @@ packages: '@ant-design/icons': 5.0.1_biqbaboplfbrettd7655fr4n2y '@ant-design/react-slick': 1.0.0_react@18.2.0 '@babel/runtime': 7.20.7 - '@ctrl/tinycolor': 3.4.1 + '@ctrl/tinycolor': 3.6.0 '@rc-component/mutate-observer': 1.0.0_biqbaboplfbrettd7655fr4n2y - '@rc-component/tour': 1.1.0_biqbaboplfbrettd7655fr4n2y + '@rc-component/tour': 1.6.0_biqbaboplfbrettd7655fr4n2y classnames: 2.3.2 copy-to-clipboard: 3.3.2 dayjs: 1.11.5 qrcode.react: 3.1.0_react@18.2.0 rc-cascader: 3.8.0_biqbaboplfbrettd7655fr4n2y rc-checkbox: 2.3.2_biqbaboplfbrettd7655fr4n2y - rc-collapse: 3.4.2_biqbaboplfbrettd7655fr4n2y + rc-collapse: 3.5.2_biqbaboplfbrettd7655fr4n2y rc-dialog: 9.0.2_biqbaboplfbrettd7655fr4n2y rc-drawer: 6.1.2_biqbaboplfbrettd7655fr4n2y rc-dropdown: 4.0.1_biqbaboplfbrettd7655fr4n2y rc-field-form: 1.27.2_biqbaboplfbrettd7655fr4n2y rc-image: 5.13.0_biqbaboplfbrettd7655fr4n2y - rc-input: 0.1.4_biqbaboplfbrettd7655fr4n2y + rc-input: 0.2.2_biqbaboplfbrettd7655fr4n2y rc-input-number: 7.4.0_biqbaboplfbrettd7655fr4n2y - rc-mentions: 1.13.1_biqbaboplfbrettd7655fr4n2y + rc-mentions: 2.0.0_biqbaboplfbrettd7655fr4n2y rc-menu: 9.8.2_biqbaboplfbrettd7655fr4n2y rc-motion: 2.6.2_biqbaboplfbrettd7655fr4n2y rc-notification: 5.0.0_biqbaboplfbrettd7655fr4n2y @@ -5180,15 +5175,15 @@ packages: rc-progress: 3.4.1_biqbaboplfbrettd7655fr4n2y rc-rate: 2.9.2_biqbaboplfbrettd7655fr4n2y rc-resize-observer: 1.2.0_biqbaboplfbrettd7655fr4n2y - rc-segmented: 2.1.0_biqbaboplfbrettd7655fr4n2y + rc-segmented: 2.1.2_biqbaboplfbrettd7655fr4n2y rc-select: 14.2.0_biqbaboplfbrettd7655fr4n2y - rc-slider: 10.0.1_biqbaboplfbrettd7655fr4n2y + rc-slider: 10.1.1_biqbaboplfbrettd7655fr4n2y rc-steps: 6.0.0_biqbaboplfbrettd7655fr4n2y rc-switch: 4.0.0_biqbaboplfbrettd7655fr4n2y rc-table: 7.30.3_biqbaboplfbrettd7655fr4n2y - rc-tabs: 12.5.5_biqbaboplfbrettd7655fr4n2y - rc-textarea: 0.4.6_biqbaboplfbrettd7655fr4n2y - rc-tooltip: 5.2.2_biqbaboplfbrettd7655fr4n2y + rc-tabs: 12.5.6_biqbaboplfbrettd7655fr4n2y + rc-textarea: 1.0.1_biqbaboplfbrettd7655fr4n2y + rc-tooltip: 5.3.1_biqbaboplfbrettd7655fr4n2y rc-tree: 5.7.2_biqbaboplfbrettd7655fr4n2y rc-tree-select: 5.6.0_biqbaboplfbrettd7655fr4n2y rc-trigger: 5.3.4_biqbaboplfbrettd7655fr4n2y @@ -11454,12 +11449,6 @@ packages: hasBin: true dev: true - /nanoid/4.0.0: - resolution: {integrity: sha512-IgBP8piMxe/gf73RTQx7hmnhwz0aaEXYakvqZyE302IXW3HyVNhdNGC+O2MwMAVhLEnvXlvKtGbtJf6wvHihCg==} - engines: {node: ^14 || ^16 || >=18} - hasBin: true - dev: false - /nanoid/4.0.1: resolution: {integrity: sha512-udKGtCCUafD3nQtJg9wBhRP3KMbPglUsgV5JVsXhvyBs/oefqb4sqMEhKBBgqZncYowu58p1prsZQBYvAj/Gww==} engines: {node: ^14 || ^16 || >=18} @@ -13263,8 +13252,8 @@ packages: react-dom: 18.2.0_react@18.2.0 dev: false - /rc-collapse/3.4.2_biqbaboplfbrettd7655fr4n2y: - resolution: {integrity: sha512-jpTwLgJzkhAgp2Wpi3xmbTbbYExg6fkptL67Uu5LCRVEj6wqmy0DHTjjeynsjOLsppHGHu41t1ELntZ0lEvS/Q==} + /rc-collapse/3.5.2_biqbaboplfbrettd7655fr4n2y: + resolution: {integrity: sha512-/TNiT3DW1t3sUCiVD/DPUYooJZ3BLA93/2rZsB3eM2bGJCCla2X9D2E4tgm7LGMQGy5Atb2lMUn2FQuvQNvavQ==} peerDependencies: react: '>=16.9.0' react-dom: '>=16.9.0' @@ -13275,7 +13264,6 @@ packages: rc-util: 5.27.1_biqbaboplfbrettd7655fr4n2y react: 18.2.0 react-dom: 18.2.0_react@18.2.0 - shallowequal: 1.1.0 dev: false /rc-dialog/9.0.2_biqbaboplfbrettd7655fr4n2y: @@ -13365,8 +13353,8 @@ packages: react-dom: 18.2.0_react@18.2.0 dev: false - /rc-input/0.1.4_biqbaboplfbrettd7655fr4n2y: - resolution: {integrity: sha512-FqDdNz+fV2dKNgfXzcSLKvC+jEs1709t7nD+WdfjrdSaOcefpgc7BUJYadc3usaING+b7ediMTfKxuJBsEFbXA==} + /rc-input/0.2.2_biqbaboplfbrettd7655fr4n2y: + resolution: {integrity: sha512-xgkVcFgtRO0Hl9hmvslZhObNyxbSpTmy3nR1Tk4XrjjZ9lFJ7GcJBy6ss30Pdb0oX36cHzLN8I7VCjBGeRNB9A==} peerDependencies: react: '>=16.0.0' react-dom: '>=16.0.0' @@ -13378,16 +13366,17 @@ packages: react-dom: 18.2.0_react@18.2.0 dev: false - /rc-mentions/1.13.1_biqbaboplfbrettd7655fr4n2y: - resolution: {integrity: sha512-FCkaWw6JQygtOz0+Vxz/M/NWqrWHB9LwqlY2RtcuFqWJNFK9njijOOzTSsBGANliGufVUzx/xuPHmZPBV0+Hgw==} + /rc-mentions/2.0.0_biqbaboplfbrettd7655fr4n2y: + resolution: {integrity: sha512-58NSeM6R5MrgYAhR2TH27JgAN7ivp3iBTmty3q6gvrrGHelPMdGxpJ5aH7AIlodCrPWLAm1lT4XoiuI4s9snXA==} peerDependencies: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: '@babel/runtime': 7.20.7 classnames: 2.3.2 + rc-input: 0.2.2_biqbaboplfbrettd7655fr4n2y rc-menu: 9.8.2_biqbaboplfbrettd7655fr4n2y - rc-textarea: 0.4.6_biqbaboplfbrettd7655fr4n2y + rc-textarea: 1.0.1_biqbaboplfbrettd7655fr4n2y rc-trigger: 5.3.4_biqbaboplfbrettd7655fr4n2y rc-util: 5.27.1_biqbaboplfbrettd7655fr4n2y react: 18.2.0 @@ -13546,8 +13535,8 @@ packages: react-dom: 18.2.0_react@18.2.0 resize-observer-polyfill: 1.5.1 - /rc-segmented/2.1.0_biqbaboplfbrettd7655fr4n2y: - resolution: {integrity: sha512-hUlonro+pYoZcwrH6Vm56B2ftLfQh046hrwif/VwLIw1j3zGt52p5mREBwmeVzXnSwgnagpOpfafspzs1asjGw==} + /rc-segmented/2.1.2_biqbaboplfbrettd7655fr4n2y: + resolution: {integrity: sha512-qGo1bCr83ESXpXVOCXjFe1QJlCAQXyi9KCiy8eX3rIMYlTeJr/ftySIaTnYsitL18SvWf5ZEHsfqIWoX0EMfFQ==} peerDependencies: react: '>=16.0.0' react-dom: '>=16.0.0' @@ -13578,8 +13567,8 @@ packages: react-dom: 18.2.0_react@18.2.0 dev: false - /rc-slider/10.0.1_biqbaboplfbrettd7655fr4n2y: - resolution: {integrity: sha512-igTKF3zBet7oS/3yNiIlmU8KnZ45npmrmHlUUio8PNbIhzMcsh+oE/r2UD42Y6YD2D/s+kzCQkzQrPD6RY435Q==} + /rc-slider/10.1.1_biqbaboplfbrettd7655fr4n2y: + resolution: {integrity: sha512-gn8oXazZISEhnmRinI89Z/JD/joAaM35jp+gDtIVSTD/JJMCCBqThqLk1SVJmvtfeiEF/kKaFY0+qt4SDHFUDw==} engines: {node: '>=8.x'} peerDependencies: react: '>=16.9.0' @@ -13590,7 +13579,6 @@ packages: rc-util: 5.27.1_biqbaboplfbrettd7655fr4n2y react: 18.2.0 react-dom: 18.2.0_react@18.2.0 - shallowequal: 1.1.0 dev: false /rc-steps/6.0.0_biqbaboplfbrettd7655fr4n2y: @@ -13654,8 +13642,8 @@ packages: react-dom: 18.2.0_react@18.2.0 dev: true - /rc-tabs/12.5.5_biqbaboplfbrettd7655fr4n2y: - resolution: {integrity: sha512-Y0k+JK4IN2cr0+MstkYK6MryvURhUc8JvHDCXujbUA6zHVTnWeTikOspGgvHPrlfZRl7WS+DPyMdEFE6RwlueQ==} + /rc-tabs/12.5.6_biqbaboplfbrettd7655fr4n2y: + resolution: {integrity: sha512-aArXHzxK7YICxe+622CZ8FlO5coMi8P7E6tXpseCPKm1gdTjUt0LrQK1/AxcrRXZXG3K4QqhlKmET0+cX5DQaQ==} engines: {node: '>=8.x'} peerDependencies: react: '>=16.9.0' @@ -13672,23 +13660,23 @@ packages: react-dom: 18.2.0_react@18.2.0 dev: false - /rc-textarea/0.4.6_biqbaboplfbrettd7655fr4n2y: - resolution: {integrity: sha512-HEKCu8nouXXayqYelQnhQm8fdH7v92pAQvfVCz+jhIPv2PHTyBxVrmoZJMn3B8cU+wdyuvRGkshngO3/TzBn4w==} + /rc-textarea/1.0.1_biqbaboplfbrettd7655fr4n2y: + resolution: {integrity: sha512-dtIm96apjJpCUcCeTtbnLGJaVlqbOqVgN0P9z+bqMSi7rcV5QVeUtBnG+jQTGk/uD183Z7jbhc8Dx7G3luDCwg==} peerDependencies: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: '@babel/runtime': 7.20.7 classnames: 2.3.2 + rc-input: 0.2.2_biqbaboplfbrettd7655fr4n2y rc-resize-observer: 1.2.0_biqbaboplfbrettd7655fr4n2y rc-util: 5.27.1_biqbaboplfbrettd7655fr4n2y react: 18.2.0 react-dom: 18.2.0_react@18.2.0 - shallowequal: 1.1.0 dev: false - /rc-tooltip/5.2.2_biqbaboplfbrettd7655fr4n2y: - resolution: {integrity: sha512-jtQzU/18S6EI3lhSGoDYhPqNpWajMtS5VV/ld1LwyfrDByQpYmw/LW6U7oFXXLukjfDHQ7Ju705A82PRNFWYhg==} + /rc-tooltip/5.3.1_biqbaboplfbrettd7655fr4n2y: + resolution: {integrity: sha512-e6H0dMD38EPaSPD2XC8dRfct27VvT2TkPdoBSuNl3RRZ5tspiY/c5xYEmGC0IrABvMBgque4Mr2SMZuliCvoiQ==} peerDependencies: react: '>=16.9.0' react-dom: '>=16.9.0' @@ -15933,10 +15921,6 @@ packages: engines: {node: '>= 10.0.0'} dev: true - /unstated-next/1.1.0: - resolution: {integrity: sha512-AAn47ZncPvgBGOvMcn8tSRxsrqwf2VdAPxLASTuLJvZt4rhKfDvUkmYZLGfclImSfTVMv7tF4ynaVxin0JjDCA==} - dev: false - /unzip-response/2.0.1: resolution: {integrity: sha512-N0XH6lqDtFH84JxptQoZYmloF4nzrQqqrAymNj+/gW60AO2AZgOcf4O/nUXJcYfyQkqvMo9lSupBZmmgvuVXlw==} engines: {node: '>=4'} From affd5c4949624921a234510100608055c3284195 Mon Sep 17 00:00:00 2001 From: liulei Date: Mon, 20 Feb 2023 08:23:53 +0800 Subject: [PATCH 67/68] =?UTF-8?q?feat(flow-designer):=20=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E6=B5=81=E8=8A=82=E7=82=B9CRUD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../FlowDesigner/components/ContextMenu.tsx | 33 ++++++-- .../flow-designer/src/FlowDesigner/index.tsx | 80 ++++++++++++++----- packages/meta-vfs/src/FlowEdgeFile/index.ts | 2 + packages/meta-vfs/src/FlowFile/index.ts | 14 +++- .../src/components/CanvasFlow/index.tsx | 20 ++++- 5 files changed, 117 insertions(+), 32 deletions(-) diff --git a/packages/flow-designer/src/FlowDesigner/components/ContextMenu.tsx b/packages/flow-designer/src/FlowDesigner/components/ContextMenu.tsx index 7f911f6..4fe82eb 100644 --- a/packages/flow-designer/src/FlowDesigner/components/ContextMenu.tsx +++ b/packages/flow-designer/src/FlowDesigner/components/ContextMenu.tsx @@ -1,12 +1,13 @@ import { useClickAway } from 'ahooks' import { Card } from 'antd' -import { FC, useRef } from 'react' -import { useReactFlow } from 'reactflow' +import { FC, MutableRefObject, useRef } from 'react' +import { OnConnectStartParams, useReactFlow } from 'reactflow' import { useAppFactory } from '@modou/asset-vfs' import { FlowNodeMetadata } from '@modou/core' import { mcss } from '@modou/css-in-js' import { FlowNodeEnum } from '@modou/flow-nodes' +import { FlowEdgeFile } from '@modou/meta-vfs/src/FlowEdgeFile' import { FlowFile } from '@modou/meta-vfs/src/FlowFile' import { FlowNodeFile } from '@modou/meta-vfs/src/FlowNodeFile' import { generateId } from '@modou/shared' @@ -16,7 +17,8 @@ export const ContextMenu: FC<{ open: boolean setOpen: (open: boolean) => void file: FlowFile -}> = ({ position, open, file, setOpen }) => { + connectionSourceRef: MutableRefObject +}> = ({ position, open, file, setOpen, connectionSourceRef }) => { const { appFactory } = useAppFactory() const { project } = useReactFlow() @@ -30,7 +32,7 @@ export const ContextMenu: FC<{ const wrapperRef = useRef(null) - useClickAway(() => { + useClickAway((e) => { setOpen(false) }, wrapperRef) @@ -49,8 +51,7 @@ export const ContextMenu: FC<{ key={node.metadata.type} className={classes.node} onClick={() => { - console.log('position', position) - FlowNodeFile.create( + const newNode = FlowNodeFile.create( { ...FlowNodeMetadata.mrSchemeToDefaultJson( appFactory.flowNodeByType[node.metadata.type].metadata @@ -64,6 +65,26 @@ export const ContextMenu: FC<{ }, file, ) + if ( + connectionSourceRef && + connectionSourceRef.current?.handleType === 'source' + ) { + FlowEdgeFile.create( + { + name: '', + id: generateId(), + source: connectionSourceRef.current + ?.nodeId as unknown as string, + target: newNode.meta.id, + sourceHandle: connectionSourceRef.current + ?.handleId as unknown as string, + targetHandle: newNode.meta.targets[0] + ?.name as unknown as string, + }, + file, + ) + } + connectionSourceRef.current = null setOpen(false) }} > diff --git a/packages/flow-designer/src/FlowDesigner/index.tsx b/packages/flow-designer/src/FlowDesigner/index.tsx index 824f282..cfd36c7 100644 --- a/packages/flow-designer/src/FlowDesigner/index.tsx +++ b/packages/flow-designer/src/FlowDesigner/index.tsx @@ -1,6 +1,11 @@ +import { useMemoizedFn } from 'ahooks' import { mapValues } from 'lodash' -import { ComponentProps, FC, useMemo, useState } from 'react' -import ReactFlow, { Controls, ReactFlowProvider } from 'reactflow' +import { ComponentProps, FC, useMemo, useRef, useState } from 'react' +import ReactFlow, { + Controls, + OnConnectStartParams, + ReactFlowProvider, +} from 'reactflow' import { useAppFactory } from '@modou/asset-vfs' import { mcss } from '@modou/css-in-js' @@ -11,6 +16,8 @@ import { getMonitorWall } from '@modou/shared' import { TurboEdge, TurboNode } from './components' import { ContextMenu } from './components/ContextMenu' +type ReactFlowProps = Required> + const NODE_TYPES = { turbo: TurboNode, } @@ -21,7 +28,7 @@ const edgeTypes = { const defaultEdgeOptions = { type: 'turbo', - markerEnd: 'edge-circle', + // markerEnd: 'edge-circle', } export const UOFlowDesigner: FC<{ file: FlowFile }> = ({ file }) => { const { appFactory } = useAppFactory() @@ -34,12 +41,59 @@ export const UOFlowDesigner: FC<{ file: FlowFile }> = ({ file }) => { ...NODE_TYPES, ...mapValues(appFactory.flowNodeByType, (f) => f.component), } + // 不要添加依赖 }, []) + const onContextMenu = useMemoizedFn< + Required>['onContextMenu'] + >((e) => { + const target = e.target as unknown as HTMLDivElement + if (!target.classList.contains('react-flow__pane')) { + return + } + + const { left, top } = getMonitorWall(target) + + setContextMenuPosition({ + x: e.clientX - left, + y: e.clientY - top, + }) + setTimeout(() => { + setContextMenuOpen(true) + }) + e.preventDefault() + }) + + const connectionRef = useRef(false) + const connectionSourceRef = useRef(null) + const onConnect = useMemoizedFn((connection) => { + connectionRef.current = true + connectionSourceRef.current = null + file.onReactFlowConnect(connection) + }) + const onConnectStart = useMemoizedFn( + (e, params) => { + connectionSourceRef.current = params + }, + ) + const onConnectEnd = useMemoizedFn((e) => { + if (connectionRef.current) { + return + } + connectionRef.current = false + onContextMenu(e as unknown as any) + }) + + // const reactFlow = useReactFlow() + // useKeyPress('Backspace', () => { + // console.log('12312', reactFlow.getEdges()) + // }) + return (
<> = ({ file }) => { edges={file.reactFlowEdges} onNodesChange={file.onReactFlowNodesChange} onEdgesChange={file.onReactFlowEdgesChange} - onConnect={file.onReactFlowConnect} + onConnect={onConnect} + onConnectEnd={onConnectEnd} + onConnectStart={onConnectStart} fitView maxZoom={1} minZoom={1} nodeTypes={nodeTypes} edgeTypes={edgeTypes} defaultEdgeOptions={defaultEdgeOptions} - onContextMenu={(e) => { - const target = e.target as unknown as HTMLDivElement - if (!target.classList.contains('react-flow__pane')) { - return - } - - const { left, top } = getMonitorWall(target) - - setContextMenuPosition({ - x: e.clientX - left, - y: e.clientY - top, - }) - setContextMenuOpen(true) - e.preventDefault() - }} + onContextMenu={onContextMenu} > diff --git a/packages/meta-vfs/src/FlowEdgeFile/index.ts b/packages/meta-vfs/src/FlowEdgeFile/index.ts index 51865f9..744ba45 100644 --- a/packages/meta-vfs/src/FlowEdgeFile/index.ts +++ b/packages/meta-vfs/src/FlowEdgeFile/index.ts @@ -34,6 +34,8 @@ export class FlowEdgeFile extends BaseFile<{}, FlowEdgeFileMeta, FlowFile> { ...this.tempMeta, ...this.meta, data: this, + // type: 'turbo', + // markerEnd: 'edge-circle', } } diff --git a/packages/meta-vfs/src/FlowFile/index.ts b/packages/meta-vfs/src/FlowFile/index.ts index 422f82b..d1d48ef 100644 --- a/packages/meta-vfs/src/FlowFile/index.ts +++ b/packages/meta-vfs/src/FlowFile/index.ts @@ -41,6 +41,9 @@ export class FlowFile extends BaseFile { reactFlowNodes: computed.struct, deleteNode: action, deleteEdge: action, + onReactFlowEdgesChange: action, + onReactFlowNodesChange: action, + onReactFlowConnect: action, }) } @@ -73,7 +76,7 @@ export class FlowFile extends BaseFile { } get reactFlowEdges() { - return this.flowEdges.map((e) => e.reactFlowMeta) + return this.flowEdges.map((edge) => edge.reactFlowMeta) } private readonly updateReactFlowEdges = ( @@ -82,7 +85,13 @@ export class FlowFile extends BaseFile { runInAction(() => { this.subFileMap.flowEdges.length = 0 edges.forEach((edge) => { - if (!edge.data) { + if (edge.data) { + edge.data.reactFlowMeta = { + ...edge.data.meta, + ...edge, + } + this.subFileMap.flowEdges.push(edge.data) + } else { edge.data = FlowEdgeFile.create( { name: '', @@ -95,7 +104,6 @@ export class FlowFile extends BaseFile { this, ) } - this.subFileMap.flowEdges.push(edge.data) }) }) } diff --git a/websites/workspace/src/components/CanvasFlow/index.tsx b/websites/workspace/src/components/CanvasFlow/index.tsx index b0d30df..e4b3cc9 100644 --- a/websites/workspace/src/components/CanvasFlow/index.tsx +++ b/websites/workspace/src/components/CanvasFlow/index.tsx @@ -1,5 +1,7 @@ +import useUrlState from '@ahooksjs/use-url-state' +import { useMemoizedFn } from 'ahooks' import { Empty } from 'antd' -import { FC, useState } from 'react' +import { FC } from 'react' import { mcss } from '@modou/css-in-js' import { PageFile } from '@modou/meta-vfs' @@ -11,11 +13,21 @@ import { FlowList } from './FlowList' export const UOCanvasFlow: FC<{ parentFile: PageFile }> = ({ parentFile }) => { - const [activeFlowId, setActiveFlowId] = useState('agdhgoasmiht') - const flowFile = parentFile.flowMap[activeFlowId] + const [urlState, setUrlState] = useUrlState<{ flowId: string }>({ + flowId: '', + }) + const flowFile = parentFile.flowMap[urlState.flowId] + const setActiveFlowId = useMemoizedFn((flowId) => { + setUrlState({ + flowId, + }) + }) return (
- + {flowFile ? ( ) : ( From f3a9a249ec41f00bdaaee95e9ed8806179969824 Mon Sep 17 00:00:00 2001 From: liulei Date: Mon, 20 Feb 2023 08:30:42 +0800 Subject: [PATCH 68/68] fix: ts type --- packages/asset-vfs/src/AssetVFS.ts | 3 ++- packages/asset-vfs/src/app-factory/AppFactoryContext.ts | 2 +- packages/asset-vfs/src/app-factory/index.ts | 3 +-- packages/flow-nodes/src/BranchNode/CaseBlock.tsx | 1 + packages/flow-nodes/src/LoopNode/index.tsx | 1 + packages/flow-nodes/src/RunScriptNode/index.tsx | 1 + packages/state-manager/src/WidgetState/index.ts | 2 +- 7 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/asset-vfs/src/AssetVFS.ts b/packages/asset-vfs/src/AssetVFS.ts index 3c4bc38..e67ec6f 100644 --- a/packages/asset-vfs/src/AssetVFS.ts +++ b/packages/asset-vfs/src/AssetVFS.ts @@ -1,6 +1,7 @@ -import { AppFactory } from '@modou/core' import { makeAutoObservable } from '@modou/reactivity' +import { AppFactory } from './app-factory' + export class AssetVFS { constructor({ appFactory }: { appFactory: AppFactory }) { this.appFactory = appFactory diff --git a/packages/asset-vfs/src/app-factory/AppFactoryContext.ts b/packages/asset-vfs/src/app-factory/AppFactoryContext.ts index 1c1f680..c3bda4f 100644 --- a/packages/asset-vfs/src/app-factory/AppFactoryContext.ts +++ b/packages/asset-vfs/src/app-factory/AppFactoryContext.ts @@ -1,6 +1,6 @@ import { createContext, memo, useContext } from 'react' -import { WidgetGroupEnum } from '@modou/core/src/types' +import { WidgetGroupEnum } from '@modou/core' import { BranchNode, LoopNode, diff --git a/packages/asset-vfs/src/app-factory/index.ts b/packages/asset-vfs/src/app-factory/index.ts index 42d8f84..4d949ef 100644 --- a/packages/asset-vfs/src/app-factory/index.ts +++ b/packages/asset-vfs/src/app-factory/index.ts @@ -1,12 +1,11 @@ import { isEqual, unionWith } from 'lodash' import { FC } from 'react' +import { WidgetGroupEnum, WidgetMetadata } from '@modou/core' import { FlowNodeInterpreter, FlowNodeMetadata, } from '@modou/core/src/flow-node' -import { WidgetGroupEnum } from '@modou/core/src/types' -import { WidgetMetadata } from '@modou/core/src/widget' import { mrToJsonSchema, schemeToDefs } from '@modou/refine' import { BaseSetterProps } from '@modou/setters/src/types' diff --git a/packages/flow-nodes/src/BranchNode/CaseBlock.tsx b/packages/flow-nodes/src/BranchNode/CaseBlock.tsx index 9910007..940afd1 100644 --- a/packages/flow-nodes/src/BranchNode/CaseBlock.tsx +++ b/packages/flow-nodes/src/BranchNode/CaseBlock.tsx @@ -75,6 +75,7 @@ export const CaseBlock: FC<{
{!hiddenCodeEditor && (
+ {/* @ts-expect-error */}
循环体
+ {/* @ts-expect-error */} + {/* @ts-expect-error */}