Skip to content

Commit

Permalink
Merge branch 'develop' into fix/component-lifecycle-not-execute
Browse files Browse the repository at this point in the history
  • Loading branch information
1ncounter committed Nov 23, 2023
2 parents 8cf0015 + 7e80d1f commit 456b8b5
Show file tree
Hide file tree
Showing 17 changed files with 265 additions and 30 deletions.
62 changes: 62 additions & 0 deletions docs/docs/api/skeleton.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion docs/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@alilc/lowcode-engine-docs",
"version": "1.2.0",
"version": "1.2.1",
"description": "低代码引擎版本化文档",
"license": "MIT",
"files": [
Expand Down
14 changes: 7 additions & 7 deletions packages/designer/src/document/node/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -440,23 +440,23 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
}

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;
}
return [];
}

if (Array.isArray(children)) {
return children;
} else if (children) {
return [children];
} else {
return [];
}

return [children];
}

isContainer(): boolean {
Expand Down Expand Up @@ -1094,7 +1094,7 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
}

/**
* 是否可执行某action
* 是否可执行某 action
*/
canPerformAction(actionName: string): boolean {
const availableActions =
Expand Down
1 change: 1 addition & 0 deletions packages/designer/src/plugin/plugin-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
61 changes: 57 additions & 4 deletions packages/designer/tests/document/node/node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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')!;
Expand Down Expand Up @@ -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')!;
Expand Down Expand Up @@ -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');
Expand Down Expand Up @@ -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();
Expand Down
31 changes: 29 additions & 2 deletions packages/editor-skeleton/src/skeleton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
IPublicTypeWidgetConfigArea,
IPublicTypeSkeletonConfig,
IPublicApiSkeleton,
IPublicTypeConfigTransducer,
} from '@alilc/lowcode-types';

const logger = new Logger({ level: 'warn', bizName: 'skeleton' });
Expand Down Expand Up @@ -111,6 +112,8 @@ export interface ISkeleton extends Omit<IPublicApiSkeleton,
export class Skeleton implements ISkeleton {
private panels = new Map<string, Panel>();

private configTransducers: IPublicTypeConfigTransducer[] = [];

private containers = new Map<string, WidgetContainer<any>>();

readonly leftArea: Area<DockConfig | PanelDockConfig | DialogDockConfig>;
Expand Down Expand Up @@ -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<string, any>): 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') {
Expand Down
1 change: 1 addition & 0 deletions packages/engine/src/engine-core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
},
};

Expand Down
25 changes: 11 additions & 14 deletions packages/plugin-outline-pane/src/controllers/tree-master.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
});
}
}
Expand Down
5 changes: 5 additions & 0 deletions packages/renderer-core/src/renderer/base.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
6 changes: 5 additions & 1 deletion packages/shell/src/api/skeleton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -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' {
Expand Down
19 changes: 18 additions & 1 deletion packages/types/src/shell/api/skeleton.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { IPublicModelSkeletonItem } from '../model';
import { IPublicTypeDisposable, IPublicTypeSkeletonConfig } from '../type';
import { IPublicTypeConfigTransducer, IPublicTypeDisposable, IPublicTypeSkeletonConfig } from '../type';

export interface IPublicApiSkeleton {

Expand Down Expand Up @@ -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;
}
2 changes: 2 additions & 0 deletions packages/types/src/shell/model/plugin-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ export interface IPublicModelPluginContext {
*/
get registerLevel(): IPublicEnumPluginRegisterLevel;

get isPluginRegisteredInWorkspace(): boolean;

get editorWindow(): IPublicModelWindow;
}

Expand Down
9 changes: 9 additions & 0 deletions packages/types/src/shell/type/config-transducer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { IPublicTypeSkeletonConfig } from '.';

export interface IPublicTypeConfigTransducer {
(prev: IPublicTypeSkeletonConfig): IPublicTypeSkeletonConfig;

level?: number;

id?: string;
}
1 change: 1 addition & 0 deletions packages/types/src/shell/type/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,4 @@ export * from './hotkey-callback-config';
export * from './hotkey-callbacks';
export * from './scrollable';
export * from './simulator-renderer';
export * from './config-transducer';
Loading

0 comments on commit 456b8b5

Please sign in to comment.