From 151748dbab0989555c1161721044ad4a2d29a2ff Mon Sep 17 00:00:00 2001 From: liujuping Date: Mon, 13 Nov 2023 13:36:07 +0800 Subject: [PATCH 01/38] docs: add before start doc --- docs/docs/guide/quickStart/demo.md | 2 +- docs/docs/guide/quickStart/intro.md | 17 ++++++++++++++++- docs/docs/guide/quickStart/start.md | 2 +- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/docs/docs/guide/quickStart/demo.md b/docs/docs/guide/quickStart/demo.md index a05a42486..ee76d5aa1 100644 --- a/docs/docs/guide/quickStart/demo.md +++ b/docs/docs/guide/quickStart/demo.md @@ -1,6 +1,6 @@ --- title: 试用低代码引擎 Demo -sidebar_position: 1 +sidebar_position: 2 --- ## 访问地址 diff --git a/docs/docs/guide/quickStart/intro.md b/docs/docs/guide/quickStart/intro.md index 661f5912f..b65baac26 100644 --- a/docs/docs/guide/quickStart/intro.md +++ b/docs/docs/guide/quickStart/intro.md @@ -1,6 +1,6 @@ --- title: 简介 -sidebar_position: 0 +sidebar_position: 1 --- # 阿里低代码引擎简介 @@ -46,3 +46,18 @@ sidebar_position: 0 **低代码设计器研发框架** 低代码引擎的核心是设计器,通过扩展、周边生态等可以产出各式各样的设计器。它不是一套可以适合所有人的低代码平台,而是帮助低代码平台的开发者,快速生产低代码平台的工具。 + +## 寻找适合您的低代码解决方案 + +帮助用户根据个人或企业需求选择合适的低代码产品。 + +| 特性/产品 | 低代码引擎 | Lab平台 | UIPaaS | +|-----------------|-----------------------------------------|-----------------------------------------|--------------------------------------------| +| **适用用户** | 前端开发者 | 需要快速搭建应用/页面的用户 | 企业用户,需要大规模部署低代码解决方案的组织 | +| **产品特点** | 设计器研发框架,适合定制开发 | 低代码平台, 可视化操作界面,易于上手 | 低代码平台孵化器,企业级功能 | +| **使用场景** | 定制和开发低代码平台的设计器部分 | 通过可视化, 快速开发应用或页面 | 帮助具有一定规模软件研发团队的的企业低成本定制低代码平台 | +| **产品关系** | 开源产品 | 基于UIPaaS技术实现, 展示了UIPaaS的部分能力 | 提供完整的低代码平台解决方案,商业产品 | +| **收费情况** | 免费 | 可免费使用(有额度限制),不提供私有化部署售卖 | 仅提供私有化部署售卖 | +| **官方网站** | [低代码引擎官网](https://lowcode-engine.cn/) | [Lab平台官网](https://lab.lowcode-engine.cn/) | [UIPaaS官网](https://uipaas.net/) | + +*注:请根据您的具体需求和条件选择合适的产品。如需更详细的信息,请访问各产品的官方网站。* diff --git a/docs/docs/guide/quickStart/start.md b/docs/docs/guide/quickStart/start.md index b2b728b9f..356f50176 100644 --- a/docs/docs/guide/quickStart/start.md +++ b/docs/docs/guide/quickStart/start.md @@ -1,5 +1,5 @@ --- -sidebar_position: 2 +sidebar_position: 3 title: 快速开始 --- From ef6a203a45ae7d8d0d4708bac28d36d10d7d4b07 Mon Sep 17 00:00:00 2001 From: JackLian Date: Mon, 13 Nov 2023 14:09:58 +0800 Subject: [PATCH 02/38] chore(docs): publish docs 1.1.16 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 27d1a17d0..c206cdf16 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.1.15", + "version": "1.1.16", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 9108e8cfabdb442064f43be0533538ebbaff7f4a Mon Sep 17 00:00:00 2001 From: liujuping Date: Mon, 13 Nov 2023 18:46:17 +0800 Subject: [PATCH 03/38] feat(types): add IPublicTypeInstanceOf to prop-types --- packages/types/src/shell/type/prop-types.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/types/src/shell/type/prop-types.ts b/packages/types/src/shell/type/prop-types.ts index a3344b059..22d84c86f 100644 --- a/packages/types/src/shell/type/prop-types.ts +++ b/packages/types/src/shell/type/prop-types.ts @@ -3,7 +3,7 @@ import { IPublicTypePropConfig } from './'; export type IPublicTypePropType = IPublicTypeBasicType | IPublicTypeRequiredType | IPublicTypeComplexType; export type IPublicTypeBasicType = 'array' | 'bool' | 'func' | 'number' | 'object' | 'string' | 'node' | 'element' | 'any'; -export type IPublicTypeComplexType = IPublicTypeOneOf | IPublicTypeOneOfType | IPublicTypeArrayOf | IPublicTypeObjectOf | IPublicTypeShape | IPublicTypeExact; +export type IPublicTypeComplexType = IPublicTypeOneOf | IPublicTypeOneOfType | IPublicTypeArrayOf | IPublicTypeObjectOf | IPublicTypeShape | IPublicTypeExact | IPublicTypeInstanceOf; export interface IPublicTypeRequiredType { type: IPublicTypeBasicType; @@ -40,3 +40,9 @@ export interface IPublicTypeExact { value: IPublicTypePropConfig[]; isRequired?: boolean; } + +export interface IPublicTypeInstanceOf { + type: 'instanceOf'; + value: IPublicTypePropConfig; + isRequired?: boolean; +} From 1020f98756c6a4886f8dd755c5fca3ff6f374876 Mon Sep 17 00:00:00 2001 From: beautiful-boyyy <66351806+beautiful-boyyy@users.noreply.github.com> Date: Tue, 14 Nov 2023 09:48:36 +0800 Subject: [PATCH 04/38] chore: remove useless code (#2643) --- .../editor-skeleton/src/components/widget-views/index.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/editor-skeleton/src/components/widget-views/index.tsx b/packages/editor-skeleton/src/components/widget-views/index.tsx index 513fc1bdd..ba49b3d1a 100644 --- a/packages/editor-skeleton/src/components/widget-views/index.tsx +++ b/packages/editor-skeleton/src/components/widget-views/index.tsx @@ -232,12 +232,8 @@ export class PanelView extends Component<{ this.lastVisible = currentVisible; if (this.lastVisible) { panel.skeleton.postEvent(SkeletonEvents.PANEL_SHOW, panel.name, panel); - // FIXME! remove this line - panel.skeleton.postEvent('leftPanel.show' as any, panel.name, panel); } else { panel.skeleton.postEvent(SkeletonEvents.PANEL_HIDE, panel.name, panel); - // FIXME! remove this line - panel.skeleton.postEvent('leftPanel.hide' as any, panel.name, panel); } } } From b697ea9ad4399a90cf2560b45beb4ae669700fbc Mon Sep 17 00:00:00 2001 From: liujuping Date: Tue, 14 Nov 2023 09:55:58 +0800 Subject: [PATCH 05/38] feat(render-core): update logger to console --- .../designer/src/builtin-simulator/index.ts | 1 + .../builtin-simulator/utils/parse-metadata.ts | 6 ++- packages/renderer-core/babel.config.js | 1 + packages/renderer-core/src/hoc/leaf.tsx | 3 +- packages/renderer-core/src/renderer/addon.tsx | 3 +- packages/renderer-core/src/renderer/base.tsx | 14 +++---- packages/renderer-core/src/renderer/temp.tsx | 3 +- packages/renderer-core/src/utils/common.ts | 6 +-- .../renderer-core/src/utils/data-helper.ts | 10 ++--- .../renderer-core/tests/utils/common.test.ts | 40 ++++++++++++++++++- .../tests/utils/data-helper.test.ts | 10 ----- 11 files changed, 66 insertions(+), 31 deletions(-) create mode 100644 packages/renderer-core/babel.config.js diff --git a/packages/designer/src/builtin-simulator/index.ts b/packages/designer/src/builtin-simulator/index.ts index 6bcee7eb7..6977fd66c 100644 --- a/packages/designer/src/builtin-simulator/index.ts +++ b/packages/designer/src/builtin-simulator/index.ts @@ -2,3 +2,4 @@ export * from './host'; export * from './host-view'; export * from './renderer'; export * from './live-editing/live-editing'; +export { LowcodeTypes } from './utils/parse-metadata'; diff --git a/packages/designer/src/builtin-simulator/utils/parse-metadata.ts b/packages/designer/src/builtin-simulator/utils/parse-metadata.ts index b84e4e698..5c81340a1 100644 --- a/packages/designer/src/builtin-simulator/utils/parse-metadata.ts +++ b/packages/designer/src/builtin-simulator/utils/parse-metadata.ts @@ -46,13 +46,15 @@ function define(propType: any = PropTypes.any, lowcodeType: string | object = {} return lowcodeCheckType; } -const LowcodeTypes: any = { +export const LowcodeTypes: any = { ...PropTypes, define, }; (window as any).PropTypes = LowcodeTypes; -(window as any).React.PropTypes = LowcodeTypes; +if ((window as any).React) { + (window as any).React.PropTypes = LowcodeTypes; +} // override primitive type checkers primitiveTypes.forEach((type) => { diff --git a/packages/renderer-core/babel.config.js b/packages/renderer-core/babel.config.js new file mode 100644 index 000000000..c5986f2bc --- /dev/null +++ b/packages/renderer-core/babel.config.js @@ -0,0 +1 @@ +module.exports = require('../../babel.config'); \ No newline at end of file diff --git a/packages/renderer-core/src/hoc/leaf.tsx b/packages/renderer-core/src/hoc/leaf.tsx index 1ff91cb14..2bb3c0b36 100644 --- a/packages/renderer-core/src/hoc/leaf.tsx +++ b/packages/renderer-core/src/hoc/leaf.tsx @@ -4,6 +4,7 @@ import { isReactComponent, cloneEnumerableProperty } from '@alilc/lowcode-utils' import { debounce } from '../utils/common'; import adapter from '../adapter'; import * as types from '../types/index'; +import logger from '../utils/logger'; export interface IComponentHocInfo { schema: any; @@ -183,7 +184,7 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, { } if (!isReactComponent(Comp)) { - console.error(`${schema.componentName} component may be has errors: `, Comp); + logger.error(`${schema.componentName} component may be has errors: `, Comp); } initRerenderEvent({ diff --git a/packages/renderer-core/src/renderer/addon.tsx b/packages/renderer-core/src/renderer/addon.tsx index 9cb114bee..211ec182f 100644 --- a/packages/renderer-core/src/renderer/addon.tsx +++ b/packages/renderer-core/src/renderer/addon.tsx @@ -2,6 +2,7 @@ import PropTypes from 'prop-types'; import baseRendererFactory from './base'; import { isEmpty } from '../utils'; import { IRendererAppHelper, IBaseRendererProps, IBaseRenderComponent } from '../types'; +import logger from '../utils/logger'; export default function addonRendererFactory(): IBaseRenderComponent { const BaseRenderer = baseRendererFactory(); @@ -32,7 +33,7 @@ export default function addonRendererFactory(): IBaseRenderComponent { const schema = props.__schema || {}; this.state = this.__parseData(schema.state || {}); if (isEmpty(props.config) || !props.config?.addonKey) { - console.warn('lce addon has wrong config'); + logger.warn('lce addon has wrong config'); this.setState({ __hasError: true, }); diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index 1980734e4..6c2a04aa7 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -56,14 +56,14 @@ export function executeLifeCycleMethod(context: any, schema: IPublicTypeNodeSche } if (typeof fn !== 'function') { - console.error(`生命周期${method}类型不符`, fn); + logger.error(`生命周期${method}类型不符`, fn); return; } try { return fn.apply(context, args); } catch (e) { - console.error(`[${schema.componentName}]生命周期${method}出错`, e); + logger.error(`[${schema.componentName}]生命周期${method}出错`, e); } } @@ -208,7 +208,7 @@ export default function baseRendererFactory(): IBaseRenderComponent { async componentDidCatch(...args: any[]) { this.__executeLifeCycleMethod('componentDidCatch', args); - console.warn(args); + logger.warn(args); } reloadDataSource = () => new Promise((resolve, reject) => { @@ -278,7 +278,7 @@ export default function baseRendererFactory(): IBaseRenderComponent { value = this.__parseExpression(value, this); } if (typeof value !== 'function') { - console.error(`custom method ${key} can not be parsed to a valid function`, value); + logger.error(`custom method ${key} can not be parsed to a valid function`, value); return; } this[key] = value.bind(this); @@ -369,7 +369,7 @@ export default function baseRendererFactory(): IBaseRenderComponent { this.setLocale = (loc: string) => { const setLocaleFn = this.appHelper?.utils?.i18n?.setLocale; if (!setLocaleFn || typeof setLocaleFn !== 'function') { - console.warn('initI18nAPIs Failed, i18n only works when appHelper.utils.i18n.setLocale() exists'); + logger.warn('initI18nAPIs Failed, i18n only works when appHelper.utils.i18n.setLocale() exists'); return undefined; } return setLocaleFn(loc); @@ -527,7 +527,7 @@ export default function baseRendererFactory(): IBaseRenderComponent { : {}; if (!Comp) { - console.error(`${schema.componentName} component is not found in components list! component list is:`, components || this.props.__container?.components); + logger.error(`${schema.componentName} component is not found in components list! component list is:`, components || this.props.__container?.components); return engine.createElement( engine.getNotFoundComponent(), { @@ -749,7 +749,7 @@ export default function baseRendererFactory(): IBaseRenderComponent { __createLoopVirtualDom = (schema: IPublicTypeNodeSchema, scope: any, parentInfo: INodeInfo, idx: number | string) => { if (isFileSchema(schema)) { - console.warn('file type not support Loop'); + logger.warn('file type not support Loop'); return null; } if (!Array.isArray(schema.loop)) { diff --git a/packages/renderer-core/src/renderer/temp.tsx b/packages/renderer-core/src/renderer/temp.tsx index 83adef7e3..1432da5fd 100644 --- a/packages/renderer-core/src/renderer/temp.tsx +++ b/packages/renderer-core/src/renderer/temp.tsx @@ -1,4 +1,5 @@ import { IBaseRenderComponent } from '../types'; +import logger from '../utils/logger'; import baseRendererFactory from './base'; export default function tempRendererFactory(): IBaseRenderComponent { @@ -41,7 +42,7 @@ export default function tempRendererFactory(): IBaseRenderComponent { } async componentDidCatch(e: any) { - console.warn(e); + logger.warn(e); this.__debug(`componentDidCatch - ${this.props.__schema.fileName}`); } diff --git a/packages/renderer-core/src/utils/common.ts b/packages/renderer-core/src/utils/common.ts index 29381b547..495744acd 100644 --- a/packages/renderer-core/src/utils/common.ts +++ b/packages/renderer-core/src/utils/common.ts @@ -183,13 +183,13 @@ export function transformArrayToMap(arr: any[], key: string, overwrite = true) { return res; } -export function checkPropTypes(value: any, name: string, rule: any, componentName: string) { +export function checkPropTypes(value: any, name: string, rule: any, componentName: string): boolean { let ruleFunction = rule; if (typeof rule === 'string') { ruleFunction = new Function(`"use strict"; const PropTypes = arguments[0]; return ${rule}`)(PropTypes2); } if (!ruleFunction || typeof ruleFunction !== 'function') { - console.warn('checkPropTypes should have a function type rule argument'); + logger.warn('checkPropTypes should have a function type rule argument'); return true; } const err = ruleFunction( @@ -203,7 +203,7 @@ export function checkPropTypes(value: any, name: string, rule: any, componentNam ReactPropTypesSecret, ); if (err) { - console.warn(err); + logger.warn(err); } return !err; } diff --git a/packages/renderer-core/src/utils/data-helper.ts b/packages/renderer-core/src/utils/data-helper.ts index d884c13c9..41bcb9bfa 100644 --- a/packages/renderer-core/src/utils/data-helper.ts +++ b/packages/renderer-core/src/utils/data-helper.ts @@ -186,7 +186,7 @@ export class DataHelper { } const { headers, ...otherProps } = otherOptionsObj || {}; if (!req) { - console.warn(`getDataSource API named ${id} not exist`); + logger.warn(`getDataSource API named ${id} not exist`); return; } @@ -215,7 +215,7 @@ export class DataHelper { try { callbackFn && callbackFn(res && res[id]); } catch (e) { - console.error('load请求回调函数报错', e); + logger.error('load请求回调函数报错', e); } return res && res[id]; }) @@ -223,7 +223,7 @@ export class DataHelper { try { callbackFn && callbackFn(null, err); } catch (e) { - console.error('load请求回调函数报错', e); + logger.error('load请求回调函数报错', e); } return err; }); @@ -300,9 +300,9 @@ export class DataHelper { return dataHandlerFun.call(this.host, data, error); } catch (e) { if (id) { - console.error(`[${id}]单个请求数据处理函数运行出错`, e); + logger.error(`[${id}]单个请求数据处理函数运行出错`, e); } else { - console.error('请求数据处理函数运行出错', e); + logger.error('请求数据处理函数运行出错', e); } } } diff --git a/packages/renderer-core/tests/utils/common.test.ts b/packages/renderer-core/tests/utils/common.test.ts index 995e55642..2ee3ed4dc 100644 --- a/packages/renderer-core/tests/utils/common.test.ts +++ b/packages/renderer-core/tests/utils/common.test.ts @@ -1,4 +1,4 @@ -// @ts-nocheck +import factoryWithTypeCheckers from 'prop-types/factoryWithTypeCheckers'; import { isSchema, isFileSchema, @@ -18,9 +18,14 @@ import { parseThisRequiredExpression, parseI18n, parseData, + checkPropTypes, } from '../../src/utils/common'; import logger from '../../src/utils/logger'; +var ReactIs = require('react-is'); + +const PropTypes = factoryWithTypeCheckers(ReactIs.isElement, true); + describe('test isSchema', () => { it('should be false when empty value is passed', () => { expect(isSchema(null)).toBeFalsy(); @@ -461,4 +466,37 @@ describe('test parseData ', () => { expect(result.__privateKey).toBeUndefined(); }); +}); + +describe('checkPropTypes', () => { + it('should validate correctly with valid prop type', () => { + expect(checkPropTypes(123, 'age', PropTypes.number, 'TestComponent')).toBe(true); + expect(checkPropTypes('123', 'age', PropTypes.string, 'TestComponent')).toBe(true); + }); + + it('should log a warning and return false with invalid prop type', () => { + expect(checkPropTypes(123, 'age', PropTypes.string, 'TestComponent')).toBe(false); + expect(checkPropTypes('123', 'age', PropTypes.number, 'TestComponent')).toBe(false); + }); + + it('should handle custom rule functions correctly', () => { + const customRule = (props, propName) => { + if (props[propName] !== 123) { + return new Error('Invalid value'); + } + }; + const result = checkPropTypes(123, 'customProp', customRule, 'TestComponent'); + expect(result).toBe(true); + }); + + + it('should interpret and validate a rule given as a string', () => { + const result = checkPropTypes(123, 'age', 'PropTypes.number', 'TestComponent'); + expect(result).toBe(true); + }); + + it('should log a warning for invalid rule type', () => { + const result = checkPropTypes(123, 'age', 123, 'TestComponent'); + expect(result).toBe(true); + }); }); \ No newline at end of file diff --git a/packages/renderer-core/tests/utils/data-helper.test.ts b/packages/renderer-core/tests/utils/data-helper.test.ts index cd4508ea8..f4b388ce9 100644 --- a/packages/renderer-core/tests/utils/data-helper.test.ts +++ b/packages/renderer-core/tests/utils/data-helper.test.ts @@ -346,11 +346,6 @@ describe('test DataHelper ', () => { result = dataHelper.handleData('fullConfigGet', mockDataHandler, { data: 'mockDataValue' }, null); expect(result).toStrictEqual({ data: 'mockDataValue' }); - // test exception - const mockError = jest.fn(); - const orginalConsole = global.console; - global.console = { error: mockError }; - // exception with id mockDataHandler = { type: 'JSFunction', @@ -358,7 +353,6 @@ describe('test DataHelper ', () => { }; result = dataHelper.handleData('fullConfigGet', mockDataHandler, { data: 'mockDataValue' }, null); expect(result).toBeUndefined(); - expect(mockError).toBeCalledWith('[fullConfigGet]单个请求数据处理函数运行出错', expect.anything()); // exception without id mockDataHandler = { @@ -367,12 +361,8 @@ describe('test DataHelper ', () => { }; result = dataHelper.handleData(null, mockDataHandler, { data: 'mockDataValue' }, null); expect(result).toBeUndefined(); - expect(mockError).toBeCalledWith('请求数据处理函数运行出错', expect.anything()); - - global.console = orginalConsole; }); - it('updateConfig should work', () => { const mockHost = { stateA: 'aValue'}; const mockDataSourceConfig = { From 944012ab3ff56bb9ec5781b1c9ecb0d14a165581 Mon Sep 17 00:00:00 2001 From: liujuping Date: Tue, 14 Nov 2023 11:46:13 +0800 Subject: [PATCH 06/38] test(designer): add test ut to sequencify --- packages/designer/jest.config.js | 1 + packages/designer/src/plugin/sequencify.ts | 58 ++++++-- .../designer/tests/plugin/sequencify.test.ts | 128 ++++++++++++++++++ 3 files changed, 177 insertions(+), 10 deletions(-) create mode 100644 packages/designer/tests/plugin/sequencify.test.ts diff --git a/packages/designer/jest.config.js b/packages/designer/jest.config.js index 1ecebd938..f0ad2e861 100644 --- a/packages/designer/jest.config.js +++ b/packages/designer/jest.config.js @@ -20,6 +20,7 @@ const jestConfig = { // testMatch: ['**/node.test.ts'], // testMatch: ['**/builtin-hotkey.test.ts'], // testMatch: ['**/selection.test.ts'], + // testMatch: ['**/plugin/sequencify.test.ts'], transformIgnorePatterns: [ `/node_modules/(?!${esModules})/`, ], diff --git a/packages/designer/src/plugin/sequencify.ts b/packages/designer/src/plugin/sequencify.ts index a312df207..9084b0a0e 100644 --- a/packages/designer/src/plugin/sequencify.ts +++ b/packages/designer/src/plugin/sequencify.ts @@ -1,19 +1,50 @@ -function sequence(tasks, names, results, missing, recursive, nest) { +interface ITaks { + [key: string]: { + name: string; + dep: string[]; + }; +} + +export function sequence({ + tasks, + names, + results, + missing, + recursive, + nest, + parentName, +}: { + tasks: ITaks; + names: string[]; + results: string[]; + missing: string[]; + recursive: string[][]; + nest: string[]; + parentName: string; +}) { names.forEach((name) => { if (results.indexOf(name) !== -1) { return; // de-dup results } const node = tasks[name]; if (!node) { - missing.push(name); + missing.push([parentName, name].filter((d => !!d)).join('.')); } else if (nest.indexOf(name) > -1) { nest.push(name); recursive.push(nest.slice(0)); - nest.pop(name); + nest.pop(); } else if (node.dep.length) { nest.push(name); - sequence(tasks, node.dep, results, missing, recursive, nest); // recurse - nest.pop(name); + sequence({ + tasks, + parentName: name, + names: node.dep, + results, + missing, + recursive, + nest, + }); // recurse + nest.pop(); } results.push(name); }); @@ -21,12 +52,19 @@ function sequence(tasks, names, results, missing, recursive, nest) { // tasks: object with keys as task names // names: array of task names -export default function (tasks, names) { - let results = []; // the final sequence - const missing = []; // missing tasks - const recursive = []; // recursive task dependencies +export default function (tasks: ITaks, names: string[]) { + let results: string[] = []; // the final sequence + const missing: string[] = []; // missing tasks + const recursive: string[][] = []; // recursive task dependencies - sequence(tasks, names, results, missing, recursive, []); + sequence({ + tasks, + names, + results, + missing, + recursive, + nest: [], + }); if (missing.length || recursive.length) { results = []; // results are incomplete at best, completely wrong at worst, remove them to avoid confusion diff --git a/packages/designer/tests/plugin/sequencify.test.ts b/packages/designer/tests/plugin/sequencify.test.ts new file mode 100644 index 000000000..89140e279 --- /dev/null +++ b/packages/designer/tests/plugin/sequencify.test.ts @@ -0,0 +1,128 @@ +import sequencify, { sequence } from '../../src/plugin/sequencify'; + +describe('sequence', () => { + it('handles tasks with no dependencies', () => { + const tasks = { + task1: { name: 'Task 1', dep: [] }, + task2: { name: 'Task 2', dep: [] } + }; + const results = []; + const missing = []; + const recursive = []; + sequence({ tasks, names: ['task1', 'task2'], results, missing, recursive, nest: [] }); + + expect(results).toEqual(['task1', 'task2']); + expect(missing).toEqual([]); + expect(recursive).toEqual([]); + }); + + it('correctly orders tasks based on dependencies', () => { + const tasks = { + task1: { name: 'Task 1', dep: [] }, + task2: { name: 'Task 2', dep: ['task1'] } + }; + const results = []; + const missing = []; + const recursive = []; + sequence({ tasks, names: ['task2', 'task1'], results, missing, recursive, nest: [] }); + + expect(results).toEqual(['task1', 'task2']); + expect(missing).toEqual([]); + expect(recursive).toEqual([]); + }); + + it('identifies missing tasks', () => { + const tasks = { + task1: { name: 'Task 1', dep: [] } + }; + const results = []; + const missing = []; + const recursive = []; + const nest = [] + sequence({ tasks, names: ['task2'], results, missing, recursive, nest }); + + expect(results).toEqual(['task2']); + expect(missing).toEqual(['task2']); + expect(recursive).toEqual([]); + expect(nest).toEqual([]); + }); + + it('detects recursive dependencies', () => { + const tasks = { + task1: { name: 'Task 1', dep: ['task2'] }, + task2: { name: 'Task 2', dep: ['task1'] } + }; + const results = []; + const missing = []; + const recursive = []; + const nest = [] + sequence({ tasks, names: ['task1', 'task2'], results, missing, recursive, nest }); + + expect(results).toEqual(['task1', 'task2', 'task1']); + expect(missing).toEqual([]); + expect(recursive).toEqual([['task1', 'task2', 'task1']]); + expect(nest).toEqual([]); + }); +}); + +describe('sequence', () => { + + it('should return tasks in sequence without dependencies', () => { + const tasks = { + task1: { name: 'Task 1', dep: [] }, + task2: { name: 'Task 2', dep: [] }, + task3: { name: 'Task 3', dep: [] } + }; + const names = ['task1', 'task2', 'task3']; + const expected = { + sequence: ['task1', 'task2', 'task3'], + missingTasks: [], + recursiveDependencies: [] + }; + expect(sequencify(tasks, names)).toEqual(expected); + }); + + it('should handle tasks with dependencies', () => { + const tasks = { + task1: { name: 'Task 1', dep: [] }, + task2: { name: 'Task 2', dep: ['task1'] }, + task3: { name: 'Task 3', dep: ['task2'] } + }; + const names = ['task3', 'task2', 'task1']; + const expected = { + sequence: ['task1', 'task2', 'task3'], + missingTasks: [], + recursiveDependencies: [] + }; + expect(sequencify(tasks, names)).toEqual(expected); + }); + + it('should identify missing tasks', () => { + const tasks = { + task1: { name: 'Task 1', dep: [] }, + task2: { name: 'Task 2', dep: ['task3'] } // task3 is missing + }; + const names = ['task1', 'task2']; + const expected = { + sequence: [], + missingTasks: ['task2.task3'], + recursiveDependencies: [] + }; + expect(sequencify(tasks, names)).toEqual(expected); + }); + + it('should detect recursive dependencies', () => { + const tasks = { + task1: { name: 'Task 1', dep: ['task2'] }, + task2: { name: 'Task 2', dep: ['task1'] } // Recursive dependency + }; + const names = ['task1', 'task2']; + const expected = { + sequence: [], + missingTasks: [], + recursiveDependencies: [['task1', 'task2', 'task1']] + }; + expect(sequencify(tasks, names)).toEqual(expected); + }); + +}); \ No newline at end of file From 736cb0e96552c557aa3f2c6d290cc3c915fb8adb Mon Sep 17 00:00:00 2001 From: beautiful-boyyy Date: Wed, 15 Nov 2023 12:09:55 +0800 Subject: [PATCH 07/38] docs: update prepare.md --- docs/docs/participate/prepare.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/docs/participate/prepare.md b/docs/docs/participate/prepare.md index c0e1d5880..acb0947f2 100644 --- a/docs/docs/participate/prepare.md +++ b/docs/docs/participate/prepare.md @@ -33,27 +33,27 @@ npm install && npm start "proxy": [ [ "https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/engine-core.js", - "http://localhost:5555/js/engine-core.js" + "http://localhost:5555/js/AliLowCodeEngine.js" ], [ "https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/engine-core.css", - "http://localhost:5555/css/engine-core.css" + "http://localhost:5555/css/AliLowCodeEngine.css" ], [ "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/react-simulator-renderer.js", - "http://localhost:5555/js/react-simulator-renderer.js" + "http://localhost:5555/js/ReactSimulatorRenderer.js" ], [ "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/react-simulator-renderer.css", - "http://localhost:5555/css/react-simulator-renderer.css" + "http://localhost:5555/css/ReactSimulatorRenderer.css" ], [ "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/rax-simulator-renderer.js", - "http://localhost:5555/js/rax-simulator-renderer.js" + "http://localhost:5555/js/RaxSimulatorRenderer.js" ], [ "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/rax-simulator-renderer.css", - "http://localhost:5555/css/rax-simulator-renderer.css" + "http://localhost:5555/css/RaxSimulatorRenderer.css" ], ] } From 6cba4bcc206c148ec87aa2aed5ffd382ae3fe438 Mon Sep 17 00:00:00 2001 From: beautiful-boyyy Date: Wed, 15 Nov 2023 12:09:55 +0800 Subject: [PATCH 08/38] docs: update prepare.md --- docs/docs/participate/prepare.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/docs/participate/prepare.md b/docs/docs/participate/prepare.md index c0e1d5880..acb0947f2 100644 --- a/docs/docs/participate/prepare.md +++ b/docs/docs/participate/prepare.md @@ -33,27 +33,27 @@ npm install && npm start "proxy": [ [ "https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/engine-core.js", - "http://localhost:5555/js/engine-core.js" + "http://localhost:5555/js/AliLowCodeEngine.js" ], [ "https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/engine-core.css", - "http://localhost:5555/css/engine-core.css" + "http://localhost:5555/css/AliLowCodeEngine.css" ], [ "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/react-simulator-renderer.js", - "http://localhost:5555/js/react-simulator-renderer.js" + "http://localhost:5555/js/ReactSimulatorRenderer.js" ], [ "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/react-simulator-renderer.css", - "http://localhost:5555/css/react-simulator-renderer.css" + "http://localhost:5555/css/ReactSimulatorRenderer.css" ], [ "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/rax-simulator-renderer.js", - "http://localhost:5555/js/rax-simulator-renderer.js" + "http://localhost:5555/js/RaxSimulatorRenderer.js" ], [ "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/rax-simulator-renderer.css", - "http://localhost:5555/css/rax-simulator-renderer.css" + "http://localhost:5555/css/RaxSimulatorRenderer.css" ], ] } From e7884fdb5a9b448aa92ca3e897def4c05bc8caa6 Mon Sep 17 00:00:00 2001 From: Super-Rz <41566502+Super-Rz@users.noreply.github.com> Date: Wed, 15 Nov 2023 14:23:07 +0800 Subject: [PATCH 09/38] fix: createIcon props (#2629) * fix: createIcon props * fix: createIcon props --- .../src/builtin-simulator/bem-tools/border-selecting.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx b/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx index 0e9d734b6..4f452727d 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx +++ b/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx @@ -143,7 +143,7 @@ function createAction(content: ReactNode | ComponentType | IPublicTypeActio }); }} > - {icon && createIcon(icon)} + {icon && createIcon(icon, { key, node: node.internalToShellNode() })} {title} ); From 058e184b21b15bcf512d796aea825b69756db537 Mon Sep 17 00:00:00 2001 From: beautiful-boyyy Date: Wed, 15 Nov 2023 15:18:18 +0800 Subject: [PATCH 10/38] fix: fixed string trim issue --- packages/renderer-core/src/renderer/base.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index 6c2a04aa7..ac4b1de12 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -901,9 +901,6 @@ export default function baseRendererFactory(): IBaseRenderComponent { }); return checkProps(res); } - if (typeof props === 'string') { - return checkProps(props.trim()); - } return checkProps(props); }; From 8898f1c4a7bb9766a0ce78632501b98942070ab4 Mon Sep 17 00:00:00 2001 From: liujuping Date: Wed, 15 Nov 2023 15:23:03 +0800 Subject: [PATCH 11/38] fix: fix engine-core classes is undefined --- packages/engine/src/engine-core.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/engine/src/engine-core.ts b/packages/engine/src/engine-core.ts index 204b9b30a..2b59ba1b6 100644 --- a/packages/engine/src/engine-core.ts +++ b/packages/engine/src/engine-core.ts @@ -54,7 +54,7 @@ import { } from '@alilc/lowcode-shell'; import { isPlainObject } from '@alilc/lowcode-utils'; import './modules/live-editing'; -import classes from './modules/classes'; +import * as classes from './modules/classes'; import symbols from './modules/symbols'; import { componentMetaParser } from './inner-plugins/component-meta-parser'; import { setterRegistry } from './inner-plugins/setter-registry'; From 0f8bc8228236439775a0429c488308ba32ab7a4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= Date: Mon, 20 Nov 2023 16:04:26 +0800 Subject: [PATCH 12/38] Update index.md --- docs/docs/article/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/docs/article/index.md b/docs/docs/article/index.md index e62f8f9d8..2de0b059e 100644 --- a/docs/docs/article/index.md +++ b/docs/docs/article/index.md @@ -6,6 +6,7 @@ - [2022/12/21 低代码多分支协同开发的建设与实践](https://mp.weixin.qq.com/s/DmwxL67htHfTUP1U966N-Q) - [2022/11/24 低代码引擎半岁啦,来跟大家唠唠嗑...](https://segmentfault.com/a/1190000042884409) - [2022/10/27 低代码技术在研发团队的应用模式探讨](https://mp.weixin.qq.com/s/Ynk_wjJbmNw7fEG6UtGZbQ) +- [基于 LowCodeEngine 的调试能力建设与实践](https://mp.weixin.qq.com/s/H8KvEOylmzLPgIuuBO0S9w) - [2022/06/23 低代码渲染那些事](https://mp.weixin.qq.com/s/yqYey76qLGYPfDtpGkVFfA) - [2022/06/16 关于 LowCode&ProCode 混合研发的思考](https://mp.weixin.qq.com/s/TY3VXjkSmsQoT47xma3wig) - [2022/04/07 磁贴布局在钉钉宜搭报表设计引擎中的实现](https://mp.weixin.qq.com/s/PSTut5ahAB8nlJ9kBpBaxw) From 8208dd3a324081eeed3718d0924a397142c0c950 Mon Sep 17 00:00:00 2001 From: AprChell Date: Mon, 20 Nov 2023 16:24:27 +0800 Subject: [PATCH 13/38] fix(exportschema): exportSchema(IPublicEnumTransformStage.Save) type conver (#2661) * fix(exportschema): exportSchema(IPublicEnumTransformStage.Save) type conver * test(prop): nullProp equals null, not --- .../designer/src/document/node/props/prop.ts | 4 ---- .../tests/document/node/props/prop.test.ts | 2 +- packages/designer/tests/fixtures/schema/form.ts | 16 ++++++++-------- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/packages/designer/src/document/node/props/prop.ts b/packages/designer/src/document/node/props/prop.ts index 01b2dc26b..e2d9f12e8 100644 --- a/packages/designer/src/document/node/props/prop.ts +++ b/packages/designer/src/document/node/props/prop.ts @@ -290,10 +290,6 @@ export class Prop implements IProp, IPropParent { } if (type === 'literal' || type === 'expression') { - // TODO 后端改造之后删除此逻辑 - if (this._value === null && stage === IPublicEnumTransformStage.Save) { - return ''; - } return this._value; } diff --git a/packages/designer/tests/document/node/props/prop.test.ts b/packages/designer/tests/document/node/props/prop.test.ts index 58c24a4ea..4424eb601 100644 --- a/packages/designer/tests/document/node/props/prop.test.ts +++ b/packages/designer/tests/document/node/props/prop.test.ts @@ -136,7 +136,7 @@ describe('Prop 类测试', () => { expect(boolProp.export(IPublicEnumTransformStage.Save)).toBe(true); expect(strProp.export(IPublicEnumTransformStage.Save)).toBe('haha'); expect(numProp.export(IPublicEnumTransformStage.Save)).toBe(1); - expect(nullProp.export(IPublicEnumTransformStage.Save)).toBe(''); + expect(nullProp.export(IPublicEnumTransformStage.Save)).toBe(null); expect(nullProp.export(IPublicEnumTransformStage.Serilize)).toBe(null); expect(expProp.export(IPublicEnumTransformStage.Save)).toEqual({ type: 'JSExpression', diff --git a/packages/designer/tests/fixtures/schema/form.ts b/packages/designer/tests/fixtures/schema/form.ts index 8da6faf9e..e8479629f 100644 --- a/packages/designer/tests/fixtures/schema/form.ts +++ b/packages/designer/tests/fixtures/schema/form.ts @@ -267,7 +267,7 @@ export default { labelTipsText: { type: 'i18n', use: 'zh-CN', - 'en-US': null, + 'en-US': '', 'zh-CN': '', }, }, @@ -337,7 +337,7 @@ export default { labelTipsText: { type: 'i18n', use: 'zh-CN', - 'en-US': null, + 'en-US': '', 'zh-CN': '', }, }, @@ -407,7 +407,7 @@ export default { labelTipsText: { type: 'i18n', use: 'zh-CN', - 'en-US': null, + 'en-US': '', 'zh-CN': '', }, }, @@ -489,7 +489,7 @@ export default { labelTipsText: { type: 'i18n', use: 'zh-CN', - 'en-US': null, + 'en-US': '', 'zh-CN': '', }, }, @@ -578,7 +578,7 @@ export default { labelTipsText: { type: 'i18n', use: 'zh-CN', - 'en-US': null, + 'en-US': '', 'zh-CN': '', }, searchDelay: 300, @@ -697,7 +697,7 @@ export default { labelTipsText: { type: 'i18n', use: 'zh-CN', - 'en-US': null, + 'en-US': '', 'zh-CN': '', }, }, @@ -789,7 +789,7 @@ export default { labelTipsText: { type: 'i18n', use: 'zh-CN', - 'en-US': null, + 'en-US': '', 'zh-CN': '', }, }, @@ -871,7 +871,7 @@ export default { labelTipsText: { type: 'i18n', use: 'zh-CN', - 'en-US': null, + 'en-US': '', 'zh-CN': '', }, }, From 3c4bd1d2d0321453b3a1fa5253b0340c3dde8afc Mon Sep 17 00:00:00 2001 From: JackLian Date: Mon, 20 Nov 2023 16:45:11 +0800 Subject: [PATCH 14/38] chore(docs): publish docs 1.1.17 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index c206cdf16..81703741a 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.1.16", + "version": "1.1.17", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 396e99aa11d442f1ace9ff138b2d4698ef57d9f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= Date: Mon, 20 Nov 2023 17:00:36 +0800 Subject: [PATCH 15/38] docs: update index.md --- docs/docs/article/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/article/index.md b/docs/docs/article/index.md index 2de0b059e..c223137b2 100644 --- a/docs/docs/article/index.md +++ b/docs/docs/article/index.md @@ -6,7 +6,7 @@ - [2022/12/21 低代码多分支协同开发的建设与实践](https://mp.weixin.qq.com/s/DmwxL67htHfTUP1U966N-Q) - [2022/11/24 低代码引擎半岁啦,来跟大家唠唠嗑...](https://segmentfault.com/a/1190000042884409) - [2022/10/27 低代码技术在研发团队的应用模式探讨](https://mp.weixin.qq.com/s/Ynk_wjJbmNw7fEG6UtGZbQ) -- [基于 LowCodeEngine 的调试能力建设与实践](https://mp.weixin.qq.com/s/H8KvEOylmzLPgIuuBO0S9w) +- [2022/08/23 基于 LowCodeEngine 的调试能力建设与实践](https://mp.weixin.qq.com/s/H8KvEOylmzLPgIuuBO0S9w) - [2022/06/23 低代码渲染那些事](https://mp.weixin.qq.com/s/yqYey76qLGYPfDtpGkVFfA) - [2022/06/16 关于 LowCode&ProCode 混合研发的思考](https://mp.weixin.qq.com/s/TY3VXjkSmsQoT47xma3wig) - [2022/04/07 磁贴布局在钉钉宜搭报表设计引擎中的实现](https://mp.weixin.qq.com/s/PSTut5ahAB8nlJ9kBpBaxw) From bf50071cc8ca2c06b70f03c16347fc85533bd8e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= Date: Mon, 20 Nov 2023 17:03:11 +0800 Subject: [PATCH 16/38] docs: update index.md --- docs/docs/video/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/docs/video/index.md b/docs/docs/video/index.md index 9f348e4e6..2f8a5f49c 100644 --- a/docs/docs/video/index.md +++ b/docs/docs/video/index.md @@ -1,4 +1,5 @@ # 官方视频 +- [2023/11/17 云栖大会|阿里开源低代码引擎及商业解决方案](https://www.bilibili.com/video/BV1Qw411H7DH) - [2023/08/03 初识低代码引擎](https://www.bilibili.com/video/BV1gu411p7TC) # 社区视频 From d47df9dc441cfc5f0a3490e2243e90473e3469e1 Mon Sep 17 00:00:00 2001 From: liujuping Date: Mon, 20 Nov 2023 17:33:53 +0800 Subject: [PATCH 17/38] style: add --workspace-left-area-width --- docs/docs/guide/expand/editor/theme.md | 1 + packages/editor-skeleton/src/layouts/workbench.less | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/docs/guide/expand/editor/theme.md b/docs/docs/guide/expand/editor/theme.md index b62fb4f28..94e434580 100644 --- a/docs/docs/guide/expand/editor/theme.md +++ b/docs/docs/guide/expand/editor/theme.md @@ -72,6 +72,7 @@ sidebar_position: 9 - `--workspace-sub-top-area-height`: 应用级二级 topArea 高度 - `--workspace-sub-top-area-margin`: 应用级二级 topArea margin - `--workspace-sub-top-area-padding`: 应用级二级 topArea padding +- `--workspace-left-area-width`: 应用级 leftArea width ### 生态使用主题色变量 diff --git a/packages/editor-skeleton/src/layouts/workbench.less b/packages/editor-skeleton/src/layouts/workbench.less index 6d0604a1f..eb86bfe04 100644 --- a/packages/editor-skeleton/src/layouts/workbench.less +++ b/packages/editor-skeleton/src/layouts/workbench.less @@ -13,6 +13,7 @@ --popup-border-radius: @popup-border-radius; --left-area-width: 48px; + --workspace-left-area-width: 48px; --right-area-width: 300px; --top-area-height: 48px; --toolbar-height: 36px; @@ -273,7 +274,7 @@ body { } .lc-left-area, .lc-workspace-left-area { height: 100%; - width: var(--left-area-width); + width: var(--workspace-left-area-width, --left-area-width); display: none; flex-shrink: 0; flex-direction: column; From 322313ceada4bf3d2011a0032f0be598c73ebeab Mon Sep 17 00:00:00 2001 From: liujuping Date: Mon, 20 Nov 2023 18:14:15 +0800 Subject: [PATCH 18/38] docs: update faq list --- docs/docs/faq/index.md | 43 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/docs/docs/faq/index.md b/docs/docs/faq/index.md index ed31bad28..5e5eee8ac 100644 --- a/docs/docs/faq/index.md +++ b/docs/docs/faq/index.md @@ -1,7 +1,46 @@ --- title: FAQ 概述 -sidebar_position: 1 +sidebar_position: -1 tags: [FAQ] --- -不定期将社区常见问题及答案维护到此处 \ No newline at end of file +不定期将社区常见问题及答案维护到此处 + +## Demo 使用 +- [渲染唯一标识(key)](/site/docs/faq/faq002) +- [点击事件如何添加参数](/site/docs/faq/faq003) +- [如何通过 API 手动调用数据源请求](/site/docs/faq/faq006) + +## 设计器定制 +- [如何通过 this.utils 使用第三方工具扩展](/site/docs/faq/faq005) +- [设置面板中的高级 tab 如何配置](/site/docs/faq/faq007) +- [插件面板如何调整位置](/site/docs/faq/faq010) + +## 源码和依赖 +- [某某 npm 包对应的源码在哪里?](/site/docs/faq/faq008) + +## 错误和报错 +- [物料出现 Component Not Found 相关报错](/site/docs/faq/faq009) +- [VERSION_PLACEHOLDER is not defined](/site/docs/faq/faq014) +- [Cannot read property 'Icon' of Undefined](/site/docs/faq/faq016) +- [windows 下运行低代码引擎源码出现报错](/site/docs/faq/faq019) +- [Can't import the named export from non ECMAScript module](/site/docs/faq/faq020) +- [Slot组件渲染报错问题](/site/docs/faq/faq023) + +## 物料相关问题 +- [如何获取物料当前处于编辑态还是渲染态](/site/docs/faq/faq011) +- [Procode 物料如何调用数据源方法](/site/docs/faq/faq012) +- [已有组件如何快速接入引擎](/site/docs/faq/faq015) +- [Modal 类组件 hidden 属性被强制设置 true](/site/docs/faq/faq013) +- [最小渲染单元配置](/site/docs/faq/faq004) +- [节点无法拖拽到 Page 下](/site/docs/faq/faq022) + +## 其他说明 +- [vue 画布支持说明](/site/docs/faq/faq017) +- [是否可以生成 Vue 页面代码?](/site/docs/faq/faq018) + +## 参与贡献 +- [提交 PR 时,明明签署过 CLA,仍被提示需要签署](/site/docs/faq/faq021) + +## 相关依赖文档 +- [build-scripts 的使用文档](/site/docs/faq/faq001) From e35c672a50dc877f5768c1092e330bfb0424cfe2 Mon Sep 17 00:00:00 2001 From: "chenkeyao.chenkeya" Date: Mon, 20 Nov 2023 21:02:05 +0800 Subject: [PATCH 19/38] feat: add new video --- docs/docs/video/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/video/index.md b/docs/docs/video/index.md index 2f8a5f49c..8ae21620b 100644 --- a/docs/docs/video/index.md +++ b/docs/docs/video/index.md @@ -1,5 +1,5 @@ # 官方视频 -- [2023/11/17 云栖大会|阿里开源低代码引擎及商业解决方案](https://www.bilibili.com/video/BV1Qw411H7DH) +- [2023/11/20 云栖大会|阿里开源低代码引擎及商业解决方案](https://www.bilibili.com/video/BV1Ku4y1w7Zr) - [2023/08/03 初识低代码引擎](https://www.bilibili.com/video/BV1gu411p7TC) # 社区视频 From 7c72261fef0324cb57fd3e42331ede0f5b680573 Mon Sep 17 00:00:00 2001 From: JackLian Date: Tue, 21 Nov 2023 10:28:27 +0800 Subject: [PATCH 20/38] chore(docs): publish docs 1.2.0 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 81703741a..cb3cb946d 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.1.17", + "version": "1.2.0", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 394b56d0cef70101709802fb6ab1fda8f0ec2e3a Mon Sep 17 00:00:00 2001 From: 1ncounter <1ncounter.100@gmail.com> Date: Wed, 22 Nov 2023 19:50:22 +0800 Subject: [PATCH 21/38] fix: recover component lifecycle and avoid execute from scope __proto__ --- packages/renderer-core/src/renderer/base.tsx | 5 +++++ .../renderer-core/src/renderer/component.tsx | 21 ------------------- 2 files changed, 5 insertions(+), 21 deletions(-) diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index ac4b1de12..dddc55e83 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -50,6 +50,11 @@ export function executeLifeCycleMethod(context: any, schema: IPublicTypeNodeSche return; } + // avoid execute lifeCycle method from __proto__'s method (it is React class Component Class lifeCycle) + if (!Object.prototype.hasOwnProperty.call(context, method) && method !== 'constructor') { + return; + } + // TODO: cache if (isJSExpression(fn) || isJSFunction(fn)) { fn = thisRequiredInJSE ? parseThisRequiredExpression(fn, context) : parseExpression(fn, context); diff --git a/packages/renderer-core/src/renderer/component.tsx b/packages/renderer-core/src/renderer/component.tsx index f9f6e8f96..3dfc1df33 100644 --- a/packages/renderer-core/src/renderer/component.tsx +++ b/packages/renderer-core/src/renderer/component.tsx @@ -46,26 +46,5 @@ export default function componentRendererFactory(): IBaseRenderComponent { return this.__renderComp(Component, this.__renderContextProvider({ compContext: this })); } - - getComponentName() { - return this.props?.componentName; - } - - /** 需要重载下面几个方法,如果在低代码组件中绑定了对应的生命周期时会出现死循环 */ - componentDidMount() { - this.__debug(`componentDidMount - ${this.getComponentName()}`); - } - getSnapshotBeforeUpdate() { - this.__debug(`getSnapshotBeforeUpdate - ${this.getComponentName()}`); - } - componentDidUpdate() { - this.__debug(`componentDidUpdate - ${this.getComponentName()}`); - } - componentWillUnmount() { - this.__debug(`componentWillUnmount - ${this.getComponentName()}`); - } - componentDidCatch() { - this.__debug(`componentDidCatch - ${this.getComponentName()}`); - } }; } From 27e914cecee34a886680db3f2bc0c69f2b62c726 Mon Sep 17 00:00:00 2001 From: andylili21 <101868030+andylili21@users.noreply.github.com> Date: Thu, 23 Nov 2023 16:05:07 +0800 Subject: [PATCH 22/38] fix: Improve code and simplify logic (#2651) * fix: Improve code and simplify logic --- packages/designer/src/document/node/node.ts | 18 +++--- .../designer/tests/document/node/node.test.ts | 61 +++++++++++++++++-- 2 files changed, 66 insertions(+), 13 deletions(-) diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts index 9effc341d..145a5a85e 100644 --- a/packages/designer/src/document/node/node.ts +++ b/packages/designer/src/document/node/node.ts @@ -440,23 +440,23 @@ export class Node } private initialChildren(children: IPublicTypeNodeData | IPublicTypeNodeData[] | undefined): IPublicTypeNodeData[] { - // FIXME! this is dirty code + const { initialChildren } = this.componentMeta.advanced; + if (children == null) { - const { initialChildren } = this.componentMeta.advanced; if (initialChildren) { if (typeof initialChildren === 'function') { return initialChildren(this.internalToShellNode()!) || []; } return initialChildren; } - } - if (Array.isArray(children)) { - return children; - } else if (children) { - return [children]; - } else { return []; } + + if (Array.isArray(children)) { + return children; + } + + return [children]; } isContainer(): boolean { @@ -1094,7 +1094,7 @@ export class Node } /** - * 是否可执行某action + * 是否可执行某 action */ canPerformAction(actionName: string): boolean { const availableActions = diff --git a/packages/designer/tests/document/node/node.test.ts b/packages/designer/tests/document/node/node.test.ts index c4717b3a0..2695d6c83 100644 --- a/packages/designer/tests/document/node/node.test.ts +++ b/packages/designer/tests/document/node/node.test.ts @@ -54,7 +54,60 @@ describe('Node 方法测试', () => { project = null; }); - it('condition group', () => {}); + // Case 1: When children is null + test('initialChildren returns result of initialChildren function when children is null ', () => { + const node = new Node(doc, { componentName: 'Button', props: { a: 1 } }); + const result = node.initialChildren(null); + // 预期结果是一个空数组 + expect(result).toEqual([]); + }); + + // Case 2: When children is undefined + test('initialChildren returns result of initialChildren function when children is null ', () => { + const node = new Node(doc, { componentName: 'Button', props: { a: 1 } }); + const result = node.initialChildren(undefined); + // 预期结果是一个空数组 + expect(result).toEqual([]); + }); + + // Case 3: When children is array + test('initialChildren returns result of initialChildren function when children is null ', () => { + const node = new Node(doc, { componentName: 'Button', props: { a: 1 } }); + const childrenArray = [{ id: 1, name: 'Child 1' }, { id: 2, name: 'Child 2' }]; + const result = node.initialChildren(childrenArray); + // 预期结果是一个数组 + expect(result).toEqual(childrenArray); + }); + + // Case 4: When children is not null and not an array + test('initialChildren returns result of initialChildren function when children is null ', () => { + const node = new Node(doc, { componentName: 'Button', props: { a: 1 } }); + const childObject = { id: 1, name: 'Child 1' }; + const result = node.initialChildren(childObject); + // 预期结果是一个数组 + expect(result).toEqual([childObject]); + }); + + // Case 5: When children 0 + test('initialChildren returns result of initialChildren function when children is null ', () => { + const node = new Node(doc, { componentName: 'Button', props: { a: 1 } }); + const childObject = 0; + const result = node.initialChildren(childObject); + // 预期结果是一个数组 + expect(result).toEqual([0]); + }); + + // Case 6: When children false + test('initialChildren returns result of initialChildren function when children is null ', () => { + const node = new Node(doc, { componentName: 'Button', props: { a: 1 } }); + const childObject = false; + const result = node.initialChildren(childObject); + // 预期结果是一个数组 + expect(result).toEqual([false]); + }); + + + it('condition group', () => { }); it('getExtraProp / setExtraProp', () => { const firstBtn = doc.getNode('node_k1ow3cbn')!; @@ -367,7 +420,7 @@ describe('Node 方法测试', () => { expect(mockFn).not.toHaveBeenCalled(); }); - it('addSlot / unlinkSlot / removeSlot', () => {}); + it('addSlot / unlinkSlot / removeSlot', () => { }); it('setProps', () => { const firstBtn = doc.getNode('node_k1ow3cbn')!; @@ -407,7 +460,7 @@ describe('Node 方法测试', () => { designer.createComponentMeta(btnMetadata); const btn = doc.getNode('node_k1ow3cbn'); // 从 componentMeta 中获取到 title 值 - expect(btn.title).toEqual({ type: 'i18n', 'zh-CN': '按钮', 'en-US': 'Button' } ); + expect(btn.title).toEqual({ type: 'i18n', 'zh-CN': '按钮', 'en-US': 'Button' }); // 从 extraProp 中获取值 btn.setExtraProp('title', 'hello button'); expect(btn.title).toBe('hello button'); @@ -546,7 +599,7 @@ describe('Node 方法测试', () => { expect(comparePosition(firstBtn, firstCard)).toBe(PositionNO.BeforeOrAfter); }); - it('getZLevelTop', () => {}); + it('getZLevelTop', () => { }); it('propsData', () => { expect(new Node(doc, { componentName: 'Leaf' }).propsData).toBeNull(); expect(new Node(doc, { componentName: 'Fragment' }).propsData).toBeNull(); From ad044f49ed9064fe1afa5195f68759a76bda5f5e Mon Sep 17 00:00:00 2001 From: liujuping Date: Thu, 23 Nov 2023 11:01:50 +0800 Subject: [PATCH 23/38] feat(utils): add workspace utils --- packages/designer/src/plugin/plugin-types.ts | 1 + packages/engine/src/engine-core.ts | 1 + .../types/src/shell/model/plugin-context.ts | 2 + packages/utils/src/index.ts | 1 + packages/utils/src/workspace.tsx | 54 +++++++++++++++++++ .../workspace/src/context/base-context.ts | 1 + 6 files changed, 60 insertions(+) create mode 100644 packages/utils/src/workspace.tsx diff --git a/packages/designer/src/plugin/plugin-types.ts b/packages/designer/src/plugin/plugin-types.ts index ac08d7d0c..6091170f0 100644 --- a/packages/designer/src/plugin/plugin-types.ts +++ b/packages/designer/src/plugin/plugin-types.ts @@ -60,6 +60,7 @@ export interface ILowCodePluginContextPrivate { set workspace(workspace: IPublicApiWorkspace); set editorWindow(window: IPublicModelWindow); set registerLevel(level: IPublicEnumPluginRegisterLevel); + set isPluginRegisteredInWorkspace(flag: boolean); } export interface ILowCodePluginContextApiAssembler { assembleApis( diff --git a/packages/engine/src/engine-core.ts b/packages/engine/src/engine-core.ts index 2b59ba1b6..3ac4c32a7 100644 --- a/packages/engine/src/engine-core.ts +++ b/packages/engine/src/engine-core.ts @@ -139,6 +139,7 @@ const pluginContextApiAssembler: ILowCodePluginContextApiAssembler = { context.logger = new Logger({ level: 'warn', bizName: `plugin:${pluginName}` }); context.workspace = workspace; context.registerLevel = IPublicEnumPluginRegisterLevel.Default; + context.isPluginRegisteredInWorkspace = false; }, }; diff --git a/packages/types/src/shell/model/plugin-context.ts b/packages/types/src/shell/model/plugin-context.ts index 1f3d3b5e8..35e7e38af 100644 --- a/packages/types/src/shell/model/plugin-context.ts +++ b/packages/types/src/shell/model/plugin-context.ts @@ -108,6 +108,8 @@ export interface IPublicModelPluginContext { */ get registerLevel(): IPublicEnumPluginRegisterLevel; + get isPluginRegisteredInWorkspace(): boolean; + get editorWindow(): IPublicModelWindow; } diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index e3f70ff80..3e37f46ba 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -30,3 +30,4 @@ export * from './is-plugin-event-name'; export * as css from './css-helper'; export { transactionManager } from './transaction-manager'; export * from './check-types'; +export * from './workspace'; diff --git a/packages/utils/src/workspace.tsx b/packages/utils/src/workspace.tsx new file mode 100644 index 000000000..446530ce8 --- /dev/null +++ b/packages/utils/src/workspace.tsx @@ -0,0 +1,54 @@ +import React, { useEffect, useState, useCallback } from 'react'; +import { IPublicModelPluginContext, IPublicEnumPluginRegisterLevel, IPublicModelWindow, IPublicModelEditorView } from '@alilc/lowcode-types'; + +/** + * 高阶组件(HOC):为组件提供 view 插件上下文。 + * + * @param {React.ComponentType} Component - 需要被封装的组件。 + * @param {string|string[]} viewName - 视图名称或视图名称数组,用于过滤特定的视图插件上下文。 + * @returns {React.ComponentType} 返回封装后的组件。 + * + * @example + * // 用法示例(函数组件): + * const EnhancedComponent = ProvideViewPluginContext(MyComponent, "viewName"); + */ +export const ProvideViewPluginContext = (Component: any, viewName?: string | string[]) => { + // 创建一个新的函数组件,以便在其中使用 Hooks + return function WithPluginContext(props: { + [key: string]: any; + + pluginContext?: IPublicModelPluginContext; + }) { + const getPluginContextFun = useCallback((editorWindow?: IPublicModelWindow | null) => { + if (!editorWindow?.currentEditorView) { + return null; + } + if (viewName) { + const items = editorWindow?.editorViews.filter(d => (d as any).viewName === viewName || (Array.isArray(viewName) && viewName.includes((d as any).viewName))); + return items[0]; + } else { + return editorWindow.currentEditorView; + } + }, []); + + const { workspace } = props.pluginContext || {}; + const [pluginContext, setPluginContext] = useState(getPluginContextFun(workspace?.window)); + + useEffect(() => { + if (workspace?.window) { + const ctx = getPluginContextFun(workspace.window); + ctx && setPluginContext(ctx); + } + return workspace?.onChangeActiveEditorView(() => { + const ctx = getPluginContextFun(workspace.window); + ctx && setPluginContext(ctx); + }); + }, [workspace, getPluginContextFun]); + + if (props.pluginContext?.registerLevel !== IPublicEnumPluginRegisterLevel.Workspace || !props.pluginContext) { + return ; + } + + return ; + }; +}; diff --git a/packages/workspace/src/context/base-context.ts b/packages/workspace/src/context/base-context.ts index b359a6139..78f32079f 100644 --- a/packages/workspace/src/context/base-context.ts +++ b/packages/workspace/src/context/base-context.ts @@ -170,6 +170,7 @@ export class BasicContext implements IBasicContext { context.editorWindow = new Window(editorWindow); } context.registerLevel = registerLevel; + context.isPluginRegisteredInWorkspace = registerLevel === IPublicEnumPluginRegisterLevel.Workspace; }, }; From 029fd1ce67739e85dd669c61ebfedf52199c2d11 Mon Sep 17 00:00:00 2001 From: liujuping Date: Thu, 23 Nov 2023 11:23:34 +0800 Subject: [PATCH 24/38] feat(outline-pane): suport registry in workspace level --- .../src/controllers/tree-master.ts | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/packages/plugin-outline-pane/src/controllers/tree-master.ts b/packages/plugin-outline-pane/src/controllers/tree-master.ts index 40162d808..ede5f0f5f 100644 --- a/packages/plugin-outline-pane/src/controllers/tree-master.ts +++ b/packages/plugin-outline-pane/src/controllers/tree-master.ts @@ -41,22 +41,19 @@ export class TreeMaster { this.initEvent(); if (pluginContext.registerLevel === IPublicEnumPluginRegisterLevel.Workspace) { this.setPluginContext(workspace.window?.currentEditorView); - workspace.onWindowRendererReady(() => { - this.setPluginContext(workspace.window?.currentEditorView); - let dispose: IPublicTypeDisposable | undefined; - const windowViewTypeChangeEvent = () => { - dispose = workspace.window?.onChangeViewType(() => { - this.setPluginContext(workspace.window?.currentEditorView); - }); - }; - - windowViewTypeChangeEvent(); - - workspace.onChangeActiveWindow(() => { - windowViewTypeChangeEvent(); + let dispose: IPublicTypeDisposable | undefined; + const windowViewTypeChangeEvent = () => { + dispose = workspace.window?.onChangeViewType(() => { this.setPluginContext(workspace.window?.currentEditorView); - dispose && dispose(); }); + }; + + windowViewTypeChangeEvent(); + + workspace.onChangeActiveWindow(() => { + windowViewTypeChangeEvent(); + this.setPluginContext(workspace.window?.currentEditorView); + dispose && dispose(); }); } } From a3fef9c13d39ac1b35b200cf0f711cf7c7c233d8 Mon Sep 17 00:00:00 2001 From: liujuping Date: Thu, 23 Nov 2023 15:32:54 +0800 Subject: [PATCH 25/38] feat(skeleton): add registerConfigTransducer API --- docs/docs/api/skeleton.md | 62 +++++++++++++++++++ packages/editor-skeleton/src/skeleton.ts | 31 +++++++++- packages/shell/src/api/skeleton.ts | 6 +- packages/types/src/shell/api/skeleton.ts | 19 +++++- .../types/src/shell/type/config-transducer.ts | 9 +++ packages/types/src/shell/type/index.ts | 1 + 6 files changed, 124 insertions(+), 4 deletions(-) create mode 100644 packages/types/src/shell/type/config-transducer.ts diff --git a/docs/docs/api/skeleton.md b/docs/docs/api/skeleton.md index c378792de..90cf1a2c1 100644 --- a/docs/docs/api/skeleton.md +++ b/docs/docs/api/skeleton.md @@ -295,6 +295,68 @@ showArea(areaName: string): void; */ hideArea(areaName: string): void; ``` + +### registerConfigTransducer +注册一个面板的配置转换器(transducer)。 + +```typescript +/** + * 注册一个面板的配置转换器(transducer)。 + * Registers a configuration transducer for a panel. + * @param {IPublicTypeConfigTransducer} transducer + * - 要注册的转换器函数。该函数接受一个配置对象(类型为 IPublicTypeSkeletonConfig)作为输入,并返回修改后的配置对象。 + * - The transducer function to be registered. This function takes a configuration object + * + * @param {number} level + * - 转换器的优先级。优先级较高的转换器会先执行。 + * - The priority level of the transducer. Transducers with higher priority levels are executed first. + * + * @param {string} [id] + * - (可选)转换器的唯一标识符。用于在需要时引用或操作特定的转换器。 + * - (Optional) A unique identifier for the transducer. Used for referencing or manipulating a specific transducer when needed. + */ +registerConfigTransducer(transducer: IPublicTypeConfigTransducer, level: number, id?: string): void; +``` + +使用示例 + +```typescript +import { IPublicModelPluginContext, IPublicTypeSkeletonConfig } from '@alilc/lowcode-types'; + +function updatePanelWidth(config: IPublicTypeSkeletonConfig) { + if (config.type === 'PanelDock') { + return { + ...config, + panelProps: { + ...(config.panelProps || {}), + width: 240, + }, + } + } + + return config; +} + +const controlPanelWidthPlugin = (ctx: IPublicModelPluginContext) => { + const { skeleton } = ctx; + (skeleton as any).registerConfigTransducer?.(updatePanelWidth, 1, 'update-panel-width'); + + return { + init() {}, + }; +}; + +controlPanelWidthPlugin.pluginName = 'controlPanelWidthPlugin'; +controlPanelWidthPlugin.meta = { + dependencies: [], + engines: { + lowcodeEngine: '^1.2.3', // 插件需要配合 ^1.0.0 的引擎才可运行 + }, +}; + +export default controlPanelWidthPlugin; +``` + ## 事件 ### onShowPanel diff --git a/packages/editor-skeleton/src/skeleton.ts b/packages/editor-skeleton/src/skeleton.ts index 89bffc4cf..13967e94d 100644 --- a/packages/editor-skeleton/src/skeleton.ts +++ b/packages/editor-skeleton/src/skeleton.ts @@ -28,6 +28,7 @@ import { IPublicTypeWidgetConfigArea, IPublicTypeSkeletonConfig, IPublicApiSkeleton, + IPublicTypeConfigTransducer, } from '@alilc/lowcode-types'; const logger = new Logger({ level: 'warn', bizName: 'skeleton' }); @@ -111,6 +112,8 @@ export interface ISkeleton extends Omit(); + private configTransducers: IPublicTypeConfigTransducer[] = []; + private containers = new Map>(); readonly leftArea: Area; @@ -448,11 +451,35 @@ export class Skeleton implements ISkeleton { return restConfig; } + registerConfigTransducer( + transducer: IPublicTypeConfigTransducer, + level = 100, + id?: string, + ) { + transducer.level = level; + transducer.id = id; + const i = this.configTransducers.findIndex((item) => item.level != null && item.level > level); + if (i < 0) { + this.configTransducers.push(transducer); + } else { + this.configTransducers.splice(i, 0, transducer); + } + } + + getRegisteredConfigTransducers(): IPublicTypeConfigTransducer[] { + return this.configTransducers; + } + add(config: IPublicTypeSkeletonConfig, extraConfig?: Record): IWidget | Widget | Panel | Stage | Dock | PanelDock | undefined { - const parsedConfig = { + const registeredTransducers = this.getRegisteredConfigTransducers(); + + const parsedConfig = registeredTransducers.reduce((prevConfig, current) => { + return current(prevConfig); + }, { ...this.parseConfig(config), ...extraConfig, - }; + }); + let { area } = parsedConfig; if (!area) { if (parsedConfig.type === 'Panel') { diff --git a/packages/shell/src/api/skeleton.ts b/packages/shell/src/api/skeleton.ts index 0d1707525..07a1727dd 100644 --- a/packages/shell/src/api/skeleton.ts +++ b/packages/shell/src/api/skeleton.ts @@ -4,7 +4,7 @@ import { SkeletonEvents, } from '@alilc/lowcode-editor-skeleton'; import { skeletonSymbol } from '../symbols'; -import { IPublicApiSkeleton, IPublicModelSkeletonItem, IPublicTypeDisposable, IPublicTypeSkeletonConfig, IPublicTypeWidgetConfigArea } from '@alilc/lowcode-types'; +import { IPublicApiSkeleton, IPublicModelSkeletonItem, IPublicTypeConfigTransducer, IPublicTypeDisposable, IPublicTypeSkeletonConfig, IPublicTypeWidgetConfigArea } from '@alilc/lowcode-types'; import { getLogger } from '@alilc/lowcode-utils'; import { SkeletonItem } from '../model/skeleton-item'; @@ -208,6 +208,10 @@ export class Skeleton implements IPublicApiSkeleton { }); return () => editor.eventBus.off(SkeletonEvents.WIDGET_HIDE, listener); } + + registerConfigTransducer(fn: IPublicTypeConfigTransducer, level: number, id?: string) { + this[skeletonSymbol].registerConfigTransducer(fn, level, id); + } } function normalizeArea(area: IPublicTypeWidgetConfigArea | undefined): 'leftArea' | 'rightArea' | 'topArea' | 'toolbar' | 'mainArea' | 'bottomArea' | 'leftFixedArea' | 'leftFloatArea' | 'stages' | 'subTopArea' { diff --git a/packages/types/src/shell/api/skeleton.ts b/packages/types/src/shell/api/skeleton.ts index 2ad561518..9a36aa469 100644 --- a/packages/types/src/shell/api/skeleton.ts +++ b/packages/types/src/shell/api/skeleton.ts @@ -1,5 +1,5 @@ import { IPublicModelSkeletonItem } from '../model'; -import { IPublicTypeDisposable, IPublicTypeSkeletonConfig } from '../type'; +import { IPublicTypeConfigTransducer, IPublicTypeDisposable, IPublicTypeSkeletonConfig } from '../type'; export interface IPublicApiSkeleton { @@ -114,4 +114,21 @@ export interface IPublicApiSkeleton { * @returns */ onHideWidget(listener: (...args: any[]) => void): IPublicTypeDisposable; + + /** + * 注册一个面板的配置转换器(transducer)。 + * Registers a configuration transducer for a panel. + * @param {IPublicTypeConfigTransducer} transducer + * - 要注册的转换器函数。该函数接受一个配置对象(类型为 IPublicTypeSkeletonConfig)作为输入,并返回修改后的配置对象。 + * - The transducer function to be registered. This function takes a configuration object (of type IPublicTypeSkeletonConfig) as input and returns a modified configuration object. + * + * @param {number} level + * - 转换器的优先级。优先级较高的转换器会先执行。 + * - The priority level of the transducer. Transducers with higher priority levels are executed first. + * + * @param {string} [id] + * - (可选)转换器的唯一标识符。用于在需要时引用或操作特定的转换器。 + * - (Optional) A unique identifier for the transducer. Used for referencing or manipulating a specific transducer when needed. + */ + registerConfigTransducer(transducer: IPublicTypeConfigTransducer, level: number, id?: string): void; } diff --git a/packages/types/src/shell/type/config-transducer.ts b/packages/types/src/shell/type/config-transducer.ts new file mode 100644 index 000000000..64c33a5c4 --- /dev/null +++ b/packages/types/src/shell/type/config-transducer.ts @@ -0,0 +1,9 @@ +import { IPublicTypeSkeletonConfig } from '.'; + +export interface IPublicTypeConfigTransducer { + (prev: IPublicTypeSkeletonConfig): IPublicTypeSkeletonConfig; + + level?: number; + + id?: string; +} diff --git a/packages/types/src/shell/type/index.ts b/packages/types/src/shell/type/index.ts index 7232ffbbd..b2fd3313f 100644 --- a/packages/types/src/shell/type/index.ts +++ b/packages/types/src/shell/type/index.ts @@ -91,3 +91,4 @@ export * from './hotkey-callback-config'; export * from './hotkey-callbacks'; export * from './scrollable'; export * from './simulator-renderer'; +export * from './config-transducer'; \ No newline at end of file From 7e80d1f863f934720915df35db3b27415a11ebb7 Mon Sep 17 00:00:00 2001 From: JackLian Date: Thu, 23 Nov 2023 16:33:45 +0800 Subject: [PATCH 26/38] chore(docs): publish docs 1.2.1 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index cb3cb946d..14d0c99e5 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.0", + "version": "1.2.1", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From dc1e0f5a49a81b3fb8c47b4a1495d06e16798fde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=94=90=E6=BE=9C?= <1ncounter.100@gmail.com> Date: Thu, 23 Nov 2023 18:58:24 +0800 Subject: [PATCH 27/38] Fix/component lifecycle not execute (#2690) * fix: recover component lifecycle and avoid execute from scope __proto__ From 6c7a52652131b0a18a03bf6f90b8730544b8be34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=94=90=E6=BE=9C?= <1ncounter.100@gmail.com> Date: Thu, 23 Nov 2023 19:28:41 +0800 Subject: [PATCH 28/38] Fix/component lifecycle not execute (#2692) * fix: recover component lifecycle and avoid execute from scope __proto__ From c643c0fc4f4c9eb90b8d273447fef04d28cfe13d Mon Sep 17 00:00:00 2001 From: 1ncounter <1ncounter.100@gmail.com> Date: Thu, 23 Nov 2023 19:35:37 +0800 Subject: [PATCH 29/38] fix(renderer-core): remove compatibility with uipaas --- packages/renderer-core/src/renderer/base.tsx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index dddc55e83..ac4b1de12 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -50,11 +50,6 @@ export function executeLifeCycleMethod(context: any, schema: IPublicTypeNodeSche return; } - // avoid execute lifeCycle method from __proto__'s method (it is React class Component Class lifeCycle) - if (!Object.prototype.hasOwnProperty.call(context, method) && method !== 'constructor') { - return; - } - // TODO: cache if (isJSExpression(fn) || isJSFunction(fn)) { fn = thisRequiredInJSE ? parseThisRequiredExpression(fn, context) : parseExpression(fn, context); From 1c2f195e8bce05284419eb7bbbba33bb97acf30e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= Date: Mon, 27 Nov 2023 16:22:29 +0800 Subject: [PATCH 30/38] docs: update skeleton.md --- docs/docs/api/skeleton.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/docs/api/skeleton.md b/docs/docs/api/skeleton.md index 90cf1a2c1..5bfa23972 100644 --- a/docs/docs/api/skeleton.md +++ b/docs/docs/api/skeleton.md @@ -69,6 +69,7 @@ skeleton.add({ props: { align: "left", icon: "wenjian", + title: '标题', // 图标下方展示的标题 description: "JS 面板", }, panelProps: { From 20bf62aed3c67753c265c38dffaa5e5a31c2b4ee Mon Sep 17 00:00:00 2001 From: JackLian Date: Mon, 27 Nov 2023 17:50:48 +0800 Subject: [PATCH 31/38] chore(docs): publish docs 1.2.2 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 14d0c99e5..e9d5b87b4 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.1", + "version": "1.2.2", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From d41f2c13d24a0270616ae4d2d2484e347ca02573 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= Date: Mon, 27 Nov 2023 21:40:25 +0800 Subject: [PATCH 32/38] docs: update material.md --- docs/docs/api/material.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/docs/docs/api/material.md b/docs/docs/api/material.md index 8b1214476..51ed4e305 100644 --- a/docs/docs/api/material.md +++ b/docs/docs/api/material.md @@ -116,6 +116,21 @@ material.setAssets(assets1); material.loadIncrementalAssets(assets2); ``` +更新特定物料的描述文件 + +```typescript +import { material } from '@alilc/lowcode-engine'; +material.loadIncrementalAssets({ + version: '', + components: [ + { + "componentName": 'Button', + "props": [{ name: 'new', title: 'new', propType: 'string' }] + } + ], +}) +``` + ### 设计器辅助层 #### addBuiltinComponentAction 在设计器辅助层增加一个扩展 action From f75b9ae61cdc46618038b3fe43e6744aa8d56f5c Mon Sep 17 00:00:00 2001 From: owenchen1004 Date: Tue, 28 Nov 2023 10:50:38 +0800 Subject: [PATCH 33/38] fix: executeLifeCycleMethod return bug in renderer --- packages/renderer-core/src/renderer/base.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index 1980734e4..640763538 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -182,7 +182,7 @@ export default function baseRendererFactory(): IBaseRenderComponent { __afterInit(_props: IBaseRendererProps) { } static getDerivedStateFromProps(props: IBaseRendererProps, state: any) { - return executeLifeCycleMethod(this, props?.__schema, 'getDerivedStateFromProps', [props, state], props.thisRequiredInJSE); + return executeLifeCycleMethod(this, props?.__schema, 'getDerivedStateFromProps', [props, state], props.thisRequiredInJSE) || null; } async getSnapshotBeforeUpdate(...args: any[]) { From b786c8fcaad1376d1d4d1316f75e283418f93913 Mon Sep 17 00:00:00 2001 From: owenchen1004 Date: Tue, 28 Nov 2023 11:04:37 +0800 Subject: [PATCH 34/38] fix: coding style update --- packages/renderer-core/src/renderer/base.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index 640763538..ebaa8eadc 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -182,7 +182,8 @@ export default function baseRendererFactory(): IBaseRenderComponent { __afterInit(_props: IBaseRendererProps) { } static getDerivedStateFromProps(props: IBaseRendererProps, state: any) { - return executeLifeCycleMethod(this, props?.__schema, 'getDerivedStateFromProps', [props, state], props.thisRequiredInJSE) || null; + const result = executeLifeCycleMethod(this, props?.__schema, 'getDerivedStateFromProps', [props, state], props.thisRequiredInJSE); + return result === undefined ? null : result; } async getSnapshotBeforeUpdate(...args: any[]) { From d199b44eca0b1fe47d1744421a275188f69533e1 Mon Sep 17 00:00:00 2001 From: liujuping Date: Tue, 28 Nov 2023 16:11:04 +0800 Subject: [PATCH 35/38] style: add --color-toolbar-background --- docs/docs/guide/expand/editor/theme.md | 73 +++++++++++++++---- .../src/layouts/workbench.less | 2 +- 2 files changed, 59 insertions(+), 16 deletions(-) diff --git a/docs/docs/guide/expand/editor/theme.md b/docs/docs/guide/expand/editor/theme.md index 94e434580..16bcf04b0 100644 --- a/docs/docs/guide/expand/editor/theme.md +++ b/docs/docs/guide/expand/editor/theme.md @@ -3,23 +3,46 @@ title: 主题色扩展 sidebar_position: 9 --- -## 主题色扩展简述 +## 简介 -通过主题色扩展,可以定制多种设计器主题。 +主题色扩展允许用户定制多样的设计器主题,增加界面的个性化和品牌识别度。 -## 主题色扩展说明 +## 设计器主题色定制 + +在 CSS 的根级别定义主题色变量可以确保这些变量在整个应用中都可用。例如: + +```css +:root { + --color-brand: rgba(0, 108, 255, 1); /* 主品牌色 */ + --color-brand-light: rgba(25, 122, 255, 1); /* 浅色品牌色 */ + --color-brand-dark: rgba(0, 96, 229, 1); /* 深色品牌色 */ +} + +``` + +将样式文件引入到你的设计器中,定义的 CSS 变量就可以改变设计器的主题色了。 ### 主题色变量 -- `--color-brand`: 品牌色 -- `--color-brand-light`: 品牌色(light) -- `--color-brand-dark`: 品牌色(dark) -- `--color-icon-normal`: 正常 icon 颜色 -- `--color-icon-hover`: icon hover 态颜色 -- `--color-icon-active`: icon active 态颜色 -- `--color-icon-reverse`: icon 反色 -- `--color-icon-disabled`: icon 禁用态颜色 -- `--color-icon-pane`: icon 面板颜色 +以下是低代码引擎设计器支持的主题色变量列表,以及它们的用途说明: + +#### 品牌相关颜色 + +- `--color-brand`: 主品牌色 +- `--color-brand-light`: 浅色品牌色 +- `--color-brand-dark`: 深色品牌色 + +#### Icon 相关颜色 + +- `--color-icon-normal`: 默认状态 +- `--color-icon-hover`: 鼠标悬停状态 +- `--color-icon-active`: 激活状态 +- `--color-icon-reverse`: 反色状态 +- `--color-icon-disabled`: 禁用状态 +- `--color-icon-pane`: 面板颜色 + +#### 线条和文本颜色 + - `--color-line-normal`: 线条颜色 - `--color-line-darken`: 线条颜色(darken) - `--color-title`: 标题颜色 @@ -29,6 +52,9 @@ sidebar_position: 9 - `--color-text-reverse`: 反色情况下,文字颜色 - `--color-text-regular`: 文字颜色(regular) - `--color-text-disabled`: 禁用态文字颜色 + +#### 字段和边框颜色 + - `--color-field-label`: field 标签颜色 - `--color-field-text`: field 文本颜色 - `--color-field-placeholder`: field placeholder 颜色 @@ -36,6 +62,9 @@ sidebar_position: 9 - `--color-field-border-hover`: hover 态下,field 边框颜色 - `--color-field-border-active`: active 态下,field 边框颜色 - `--color-field-background`: field 背景色 + +#### 状态颜色 + - `--color-success`: success 颜色 - `--colo-success-dark`: success 颜色(dark) - `--color-success-light`: success 颜色(light) @@ -50,7 +79,9 @@ sidebar_position: 9 - `--color-error-light`: error 颜色(light) - `--color-purple`: purple 颜色 - `--color-brown`: brown 颜色 -- `--color-pane-background`: 面板背景色 + +#### 区块背景色 + - `--color-block-background-normal`: 区块背景色 - `--color-block-background-light`: 区块背景色(light), 作用于画布组件 hover 时遮罩背景色。 - `--color-block-background-shallow`: 区块背景色 shallow @@ -61,20 +92,30 @@ sidebar_position: 9 - `--color-block-background-error`: 区块背景色(error) - `--color-block-background-success`: 区块背景色(success) - `--color-block-background-deep-dark`: 区块背景色(deep-dark),作用于多个组件同时拖拽的背景色。 + +#### 其他区域背景色 + - `--color-layer-mask-background`: 拖拽元素时,元素原来位置的遮罩背景色 - `--color-layer-tooltip-background`: tooltip 背景色 +- `--color-pane-background`: 面板背景色 - `--color-background`: 设计器主要背景色 - `--color-top-area-background`: topArea 背景色,优先级大于 `--color-pane-background` - `--color-left-area-background`: leftArea 背景色,优先级大于 `--color-pane-background` +- `--color-toolbar-background`: toolbar 背景色,优先级大于 `--color-pane-background` - `--color-workspace-left-area-background`: 应用级 leftArea 背景色,优先级大于 `--color-pane-background` - `--color-workspace-top-area-background`: 应用级 topArea 背景色,优先级大于 `--color-pane-background` - `--color-workspace-sub-top-area-background`: 应用级二级 topArea 背景色,优先级大于 `--color-pane-background` + +#### 其他变量 + - `--workspace-sub-top-area-height`: 应用级二级 topArea 高度 - `--workspace-sub-top-area-margin`: 应用级二级 topArea margin - `--workspace-sub-top-area-padding`: 应用级二级 topArea padding - `--workspace-left-area-width`: 应用级 leftArea width -### 生态使用主题色变量 + + +### 低代码引擎生态主题色定制 插件、物料、设置器等生态为了支持主题色需要对样式进行改造,需要对生态中的样式升级为 css 变量。例如: @@ -87,6 +128,8 @@ background: var(--color-brand, #006cff); ``` +这里 `var(--color-brand, #默认色)` 表示使用 `--color-brand` 变量,如果该变量未定义,则使用默认颜色(#默认色)。 + ### fusion 物料进行主题色扩展 -如果使用了 fusion 组件,可以通过 https://fusion.alibaba-inc.com/ 平台进行主题色定制。 \ No newline at end of file +如果使用了 fusion 组件时,可以通过 [fusion 平台](https://fusion.design/) 进行主题色定制。在平台上,您可以选择不同的主题颜色,并直接应用于您的 fusion 组件,这样可以无缝地集成到您的应用设计中。 \ No newline at end of file diff --git a/packages/editor-skeleton/src/layouts/workbench.less b/packages/editor-skeleton/src/layouts/workbench.less index eb86bfe04..1f0eae8ec 100644 --- a/packages/editor-skeleton/src/layouts/workbench.less +++ b/packages/editor-skeleton/src/layouts/workbench.less @@ -366,7 +366,7 @@ body { .lc-toolbar { display: flex; height: var(--toolbar-height); - background-color: var(--color-pane-background); + background-color: var(--color-toolbar-background, var(--color-pane-background)); padding: 8px 16px; .lc-toolbar-center { display: flex; From d703e64ac958de5e91d34f4741b49b94a6b467ea Mon Sep 17 00:00:00 2001 From: JackLian Date: Wed, 29 Nov 2023 11:10:29 +0800 Subject: [PATCH 36/38] chore(docs): publish docs 1.2.3 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index e9d5b87b4..00887a758 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.2", + "version": "1.2.3", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 19bf6ad28456feab9b58de3a00023898c72d8fde Mon Sep 17 00:00:00 2001 From: liujuping Date: Wed, 29 Nov 2023 11:29:33 +0800 Subject: [PATCH 37/38] style: add --color-toolbar-background --- packages/editor-skeleton/src/layouts/workbench.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/editor-skeleton/src/layouts/workbench.less b/packages/editor-skeleton/src/layouts/workbench.less index 1f0eae8ec..2cddb2537 100644 --- a/packages/editor-skeleton/src/layouts/workbench.less +++ b/packages/editor-skeleton/src/layouts/workbench.less @@ -452,7 +452,7 @@ body { .lc-toolbar { display: flex; height: var(--toolbar-height); - background-color: var(--color-pane-background); + background-color: var(--color-toolbar-background, var(--color-pane-background)); padding: 8px 16px; .lc-toolbar-center { display: flex; From 1a328bd1f63a27074ba4b07c9b866ef85038e6e2 Mon Sep 17 00:00:00 2001 From: liujuping Date: Thu, 30 Nov 2023 17:36:55 +0800 Subject: [PATCH 38/38] style: fix --workspace-left-area-width style bug --- docs/docs/guide/expand/editor/theme.md | 1 + packages/editor-skeleton/src/layouts/workbench.less | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/docs/docs/guide/expand/editor/theme.md b/docs/docs/guide/expand/editor/theme.md index 16bcf04b0..35a77f2ac 100644 --- a/docs/docs/guide/expand/editor/theme.md +++ b/docs/docs/guide/expand/editor/theme.md @@ -112,6 +112,7 @@ sidebar_position: 9 - `--workspace-sub-top-area-margin`: 应用级二级 topArea margin - `--workspace-sub-top-area-padding`: 应用级二级 topArea padding - `--workspace-left-area-width`: 应用级 leftArea width +- `--left-area-width`: leftArea width diff --git a/packages/editor-skeleton/src/layouts/workbench.less b/packages/editor-skeleton/src/layouts/workbench.less index 2cddb2537..565b6f07d 100644 --- a/packages/editor-skeleton/src/layouts/workbench.less +++ b/packages/editor-skeleton/src/layouts/workbench.less @@ -443,6 +443,10 @@ body { min-height: 0; position: relative; + > .lc-left-float-pane { + left: calc(var(--workspace-left-area-width, var(--left-area-width)) + 1px); + } + .lc-workspace-workbench-center { flex: 1; display: flex;