mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2025-12-12 11:20:11 +00:00
fix: remove console.log statements, update test, and purge children in NodeChildren class
This commit is contained in:
parent
d7dfde5452
commit
71f9e08cb2
@ -22,6 +22,7 @@ const jestConfig = {
|
||||
// testMatch: ['**/selection.test.ts'],
|
||||
// testMatch: ['**/plugin/sequencify.test.ts'],
|
||||
// testMatch: ['**/builtin-simulator/utils/parse-metadata.test.ts'],
|
||||
// testMatch: ['**/setting/setting-top-entry.test.ts'],
|
||||
transformIgnorePatterns: [
|
||||
`/node_modules/(?!${esModules})/`,
|
||||
],
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import { ReactNode } from 'react';
|
||||
import {
|
||||
IPublicTypeTitleContent,
|
||||
IPublicTypeSetterType,
|
||||
@ -7,18 +6,15 @@ import {
|
||||
IPublicTypeFieldConfig,
|
||||
IPublicTypeCustomView,
|
||||
IPublicTypeDisposable,
|
||||
IPublicModelSettingField,
|
||||
IBaseModelSettingField,
|
||||
} from '@alilc/lowcode-types';
|
||||
import type {
|
||||
IPublicTypeSetValueOptions,
|
||||
} from '@alilc/lowcode-types';
|
||||
import { Transducer } from './utils';
|
||||
import { ISettingPropEntry, SettingPropEntry } from './setting-prop-entry';
|
||||
import { SettingPropEntry } from './setting-prop-entry';
|
||||
import { computed, obx, makeObservable, action, untracked, intl } from '@alilc/lowcode-editor-core';
|
||||
import { cloneDeep, isCustomView, isDynamicSetter, isJSExpression } from '@alilc/lowcode-utils';
|
||||
import { ISettingTopEntry } from './setting-top-entry';
|
||||
import { IComponentMeta, INode } from '@alilc/lowcode-designer';
|
||||
|
||||
function getSettingFieldCollectorKey(parent: ISettingTopEntry | ISettingField, config: IPublicTypeFieldConfig) {
|
||||
let cur = parent;
|
||||
@ -32,53 +28,9 @@ function getSettingFieldCollectorKey(parent: ISettingTopEntry | ISettingField, c
|
||||
return path.join('.');
|
||||
}
|
||||
|
||||
export interface ISettingField extends ISettingPropEntry, Omit<IBaseModelSettingField<
|
||||
ISettingTopEntry,
|
||||
ISettingField,
|
||||
IComponentMeta,
|
||||
INode
|
||||
>, 'setValue' | 'key' | 'node'> {
|
||||
readonly isSettingField: true;
|
||||
export interface ISettingField extends SettingField {}
|
||||
|
||||
readonly isRequired: boolean;
|
||||
|
||||
readonly isGroup: boolean;
|
||||
|
||||
extraProps: IPublicTypeFieldExtraProps;
|
||||
|
||||
get items(): Array<ISettingField | IPublicTypeCustomView>;
|
||||
|
||||
get title(): string | ReactNode | undefined;
|
||||
|
||||
get setter(): IPublicTypeSetterType | null;
|
||||
|
||||
get expanded(): boolean;
|
||||
|
||||
get valueState(): number;
|
||||
|
||||
setExpanded(value: boolean): void;
|
||||
|
||||
purge(): void;
|
||||
|
||||
setValue(
|
||||
val: any,
|
||||
isHotValue?: boolean,
|
||||
force?: boolean,
|
||||
extraOptions?: IPublicTypeSetValueOptions,
|
||||
): void;
|
||||
|
||||
clearValue(): void;
|
||||
|
||||
valueChange(options: IPublicTypeSetValueOptions): void;
|
||||
|
||||
createField(config: IPublicTypeFieldConfig): ISettingField;
|
||||
|
||||
onEffect(action: () => void): IPublicTypeDisposable;
|
||||
|
||||
internalToShellField(): IPublicModelSettingField;
|
||||
}
|
||||
|
||||
export class SettingField extends SettingPropEntry implements ISettingField {
|
||||
export class SettingField extends SettingPropEntry {
|
||||
readonly isSettingField = true;
|
||||
|
||||
readonly isRequired: boolean;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { IPublicTypeCustomView, IPublicModelEditor, IPublicModelSettingTopEntry, IPublicApiSetters } from '@alilc/lowcode-types';
|
||||
import { isCustomView } from '@alilc/lowcode-utils';
|
||||
import { computed, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core';
|
||||
import { computed, IEventBus, createModuleEventBus, obx, makeObservable } from '@alilc/lowcode-editor-core';
|
||||
import { ISettingEntry } from './setting-entry-type';
|
||||
import { ISettingField, SettingField } from './setting-field';
|
||||
import { INode } from '../../document';
|
||||
@ -14,33 +14,17 @@ function generateSessionId(nodes: INode[]) {
|
||||
.join(',');
|
||||
}
|
||||
|
||||
export interface ISettingTopEntry extends ISettingEntry, IPublicModelSettingTopEntry<
|
||||
export interface ISettingTopEntry extends SettingTopEntry {}
|
||||
|
||||
export class SettingTopEntry implements ISettingEntry, IPublicModelSettingTopEntry<
|
||||
INode,
|
||||
ISettingField
|
||||
> {
|
||||
readonly top: ISettingTopEntry;
|
||||
|
||||
readonly parent: ISettingTopEntry;
|
||||
|
||||
readonly path: never[];
|
||||
|
||||
items: Array<ISettingField | IPublicTypeCustomView>;
|
||||
|
||||
componentMeta: IComponentMeta | null;
|
||||
|
||||
purge(): void;
|
||||
|
||||
getExtraPropValue(propName: string): void;
|
||||
|
||||
setExtraPropValue(propName: string, value: any): void;
|
||||
}
|
||||
|
||||
export class SettingTopEntry implements ISettingTopEntry {
|
||||
private emitter: IEventBus = createModuleEventBus('SettingTopEntry');
|
||||
|
||||
private _items: Array<SettingField | IPublicTypeCustomView> = [];
|
||||
private _items: Array<ISettingField | IPublicTypeCustomView> = [];
|
||||
|
||||
private _componentMeta: IComponentMeta | null = null;
|
||||
private _componentMeta: IComponentMeta | null | undefined = null;
|
||||
|
||||
private _isSame = true;
|
||||
|
||||
@ -75,7 +59,7 @@ export class SettingTopEntry implements ISettingTopEntry {
|
||||
}
|
||||
|
||||
get isLocked(): boolean {
|
||||
return this.first.isLocked;
|
||||
return this.first?.isLocked ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -87,7 +71,11 @@ export class SettingTopEntry implements ISettingTopEntry {
|
||||
|
||||
readonly id: string;
|
||||
|
||||
readonly first: INode;
|
||||
@computed get first(): INode | null {
|
||||
return this._first;
|
||||
}
|
||||
|
||||
@obx.ref _first: INode | null;
|
||||
|
||||
readonly designer: IDesigner | undefined;
|
||||
|
||||
@ -96,12 +84,14 @@ export class SettingTopEntry implements ISettingTopEntry {
|
||||
disposeFunctions: any[] = [];
|
||||
|
||||
constructor(readonly editor: IPublicModelEditor, readonly nodes: INode[]) {
|
||||
makeObservable(this);
|
||||
|
||||
if (!Array.isArray(nodes) || nodes.length < 1) {
|
||||
throw new ReferenceError('nodes should not be empty');
|
||||
}
|
||||
this.id = generateSessionId(nodes);
|
||||
this.first = nodes[0];
|
||||
this.designer = this.first.document?.designer;
|
||||
this._first = nodes[0];
|
||||
this.designer = this._first.document?.designer;
|
||||
this.setters = editor.get('setters') as IPublicApiSetters;
|
||||
|
||||
// setups
|
||||
@ -116,7 +106,7 @@ export class SettingTopEntry implements ISettingTopEntry {
|
||||
private setupComponentMeta() {
|
||||
// todo: enhance compile a temp configure.compiled
|
||||
const { first } = this;
|
||||
const meta = first.componentMeta;
|
||||
const meta = first?.componentMeta;
|
||||
const l = this.nodes.length;
|
||||
let theSame = true;
|
||||
for (let i = 1; i < l; i++) {
|
||||
@ -160,7 +150,7 @@ export class SettingTopEntry implements ISettingTopEntry {
|
||||
/**
|
||||
* 获取当前属性值
|
||||
*/
|
||||
@computed getValue(): any {
|
||||
getValue(): any {
|
||||
return this.first?.propsData;
|
||||
}
|
||||
|
||||
@ -202,14 +192,14 @@ export class SettingTopEntry implements ISettingTopEntry {
|
||||
* 获取子级属性值
|
||||
*/
|
||||
getPropValue(propName: string | number): any {
|
||||
return this.first.getProp(propName.toString(), true)?.getValue();
|
||||
return this.first?.getProp(propName.toString(), true)?.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取顶层附属属性值
|
||||
*/
|
||||
getExtraPropValue(propName: string) {
|
||||
return this.first.getExtraProp(propName, false)?.getValue();
|
||||
return this.first?.getExtraProp(propName, false)?.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -244,8 +234,9 @@ export class SettingTopEntry implements ISettingTopEntry {
|
||||
this.disposeItems();
|
||||
this._settingFieldMap = {};
|
||||
this.emitter.removeAllListeners();
|
||||
this.disposeFunctions.forEach(f => f());
|
||||
this.disposeFunctions.forEach(f => f?.());
|
||||
this.disposeFunctions = [];
|
||||
this._first = null;
|
||||
}
|
||||
|
||||
getProp(propName: string | number) {
|
||||
@ -274,7 +265,7 @@ export class SettingTopEntry implements ISettingTopEntry {
|
||||
}
|
||||
|
||||
getPage() {
|
||||
return this.first.document;
|
||||
return this.first?.document;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -292,6 +283,7 @@ export class SettingTopEntry implements ISettingTopEntry {
|
||||
interface Purgeable {
|
||||
purge(): void;
|
||||
}
|
||||
|
||||
function isPurgeable(obj: any): obj is Purgeable {
|
||||
return obj && obj.purge;
|
||||
}
|
||||
|
||||
@ -91,6 +91,7 @@ export class NodeChildren implements Omit<IPublicModelNodeChildren<INode>,
|
||||
node.import(item);
|
||||
} else {
|
||||
node = this.owner.document?.createNode(item);
|
||||
child?.purge();
|
||||
}
|
||||
|
||||
if (node) {
|
||||
@ -98,6 +99,10 @@ export class NodeChildren implements Omit<IPublicModelNodeChildren<INode>,
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = data.length; i < originChildren.length; i++) {
|
||||
originChildren[i].purge();
|
||||
}
|
||||
|
||||
this.children = children;
|
||||
this.internalInitParent();
|
||||
if (!shallowEqual(children, originChildren)) {
|
||||
|
||||
@ -987,7 +987,7 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
|
||||
this.autoruns?.forEach((dispose) => dispose());
|
||||
this.props.purge();
|
||||
this.settingEntry?.purge();
|
||||
// this.document.destroyNode(this);
|
||||
this.children?.purge();
|
||||
}
|
||||
|
||||
internalPurgeStart() {
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
import '../../fixtures/window';
|
||||
import { Editor, Setters } from '@alilc/lowcode-editor-core';
|
||||
import { Editor, Setters, reaction } from '@alilc/lowcode-editor-core';
|
||||
import { Node } from '../../../src/document/node/node';
|
||||
import { Designer } from '../../../src/designer/designer';
|
||||
import settingSchema from '../../fixtures/schema/setting';
|
||||
import { SettingTopEntry } from '../../../src/designer/setting/setting-top-entry';
|
||||
import divMeta from '../../fixtures/component-metadata/div';
|
||||
import { shellModelFactory } from '../../../../engine/src/modules/shell-model-factory';
|
||||
|
||||
@ -109,6 +110,26 @@ describe('setting-top-entry 测试', () => {
|
||||
expect(settingEntry.items).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should notify when _first is set to null', (done) => {
|
||||
// 创建一个简单的INode数组用于初始化SettingTopEntry实例
|
||||
const nodes = [{ id: '1', propsData: {} }, { id: '2', propsData: {} }];
|
||||
const entry = new SettingTopEntry(editor as any, nodes as any);
|
||||
|
||||
// 使用MobX的reaction来观察_first属性的变化
|
||||
const dispose = reaction(
|
||||
() => entry.first,
|
||||
(first) => {
|
||||
if (first === null) {
|
||||
dispose(); // 清理reaction监听
|
||||
done(); // 结束测试
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// 执行purge方法,期望_first被设置为null,触发reaction回调
|
||||
entry.purge();
|
||||
});
|
||||
|
||||
it('vision 兼容测试', () => {
|
||||
designer.createComponentMeta(divMeta);
|
||||
designer.project.open(settingSchema);
|
||||
|
||||
@ -541,8 +541,6 @@ export class Hotkey implements Omit<IPublicApiHotkey, 'bind' | 'callbacks'> {
|
||||
}
|
||||
|
||||
private handleKeyEvent(e: KeyboardEvent): void {
|
||||
console.log(e);
|
||||
// debugger;
|
||||
if (!this.isActivate) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { Node, Designer, Selection, SettingTopEntry } from '@alilc/lowcode-designer';
|
||||
import { INode, IDesigner, Selection, SettingTopEntry } from '@alilc/lowcode-designer';
|
||||
import { Editor, obx, computed, makeObservable, action, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core';
|
||||
|
||||
function generateSessionId(nodes: Node[]) {
|
||||
function generateSessionId(nodes: INode[]) {
|
||||
return nodes
|
||||
.map((node) => node.id)
|
||||
.sort()
|
||||
@ -29,7 +29,11 @@ export class SettingsMain {
|
||||
|
||||
private disposeListener: () => void;
|
||||
|
||||
private designer?: Designer;
|
||||
private _designer?: IDesigner;
|
||||
|
||||
get designer(): IDesigner | undefined {
|
||||
return this._designer;
|
||||
}
|
||||
|
||||
constructor(readonly editor: Editor) {
|
||||
makeObservable(this);
|
||||
@ -49,12 +53,12 @@ export class SettingsMain {
|
||||
this.editor.removeListener('designer.selection.change', setupSelection);
|
||||
};
|
||||
const designer = await this.editor.onceGot('designer');
|
||||
this.designer = designer;
|
||||
this._designer = designer;
|
||||
setupSelection(designer.currentSelection);
|
||||
}
|
||||
|
||||
@action
|
||||
private setup(nodes: Node[]) {
|
||||
private setup(nodes: INode[]) {
|
||||
// check nodes change
|
||||
const sessionId = generateSessionId(nodes);
|
||||
if (sessionId === this._sessionId) {
|
||||
@ -66,15 +70,15 @@ export class SettingsMain {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.designer) {
|
||||
this.designer = nodes[0].document.designer;
|
||||
if (!this._designer) {
|
||||
this._designer = nodes[0].document.designer;
|
||||
}
|
||||
// 当节点只有一个时,复用 node 上挂载的 settingEntry,不会产生平行的两个实例,这样在整个系统中对
|
||||
// 某个节点操作的 SettingTopEntry 只有一个实例,后续的 getProp() 也会拿到相同的 SettingField 实例
|
||||
if (nodes.length === 1) {
|
||||
this._settings = nodes[0].settingEntry;
|
||||
} else {
|
||||
this._settings = this.designer.createSettingEntry(nodes);
|
||||
this._settings = this._designer.createSettingEntry(nodes);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Tab, Breadcrumb } from '@alifd/next';
|
||||
import { Title, observer, Editor, obx, globalContext, engineConfig, makeObservable } from '@alilc/lowcode-editor-core';
|
||||
import { Node, SettingField, isSettingField, INode } from '@alilc/lowcode-designer';
|
||||
import { ISettingField, INode } from '@alilc/lowcode-designer';
|
||||
import classNames from 'classnames';
|
||||
import { SettingsMain } from './main';
|
||||
import { SettingsPane } from './settings-pane';
|
||||
import { StageBox } from '../stage-box';
|
||||
import { SkeletonContext } from '../../context';
|
||||
import { intl } from '../../locale';
|
||||
import { createIcon } from '@alilc/lowcode-utils';
|
||||
import { createIcon, isSettingField } from '@alilc/lowcode-utils';
|
||||
|
||||
interface ISettingsPrimaryPaneProps {
|
||||
engineEditor: Editor;
|
||||
@ -53,8 +53,7 @@ export class SettingsPrimaryPane extends Component<ISettingsPrimaryPaneProps, {
|
||||
}
|
||||
|
||||
renderBreadcrumb() {
|
||||
const { settings, editor } = this.main;
|
||||
// const shouldIgnoreRoot = config.props?.ignoreRoot;
|
||||
const { settings, editor, designer } = this.main;
|
||||
const { shouldIgnoreRoot } = this.state;
|
||||
if (!settings) {
|
||||
return null;
|
||||
@ -73,10 +72,9 @@ export class SettingsPrimaryPane extends Component<ISettingsPrimaryPaneProps, {
|
||||
);
|
||||
}
|
||||
|
||||
const designer = editor.get('designer');
|
||||
const current = designer?.currentSelection?.getNodes()?.[0];
|
||||
let node: INode | null = settings.first;
|
||||
const focusNode = node.document?.focusNode;
|
||||
const focusNode = node?.document?.focusNode;
|
||||
|
||||
const items = [];
|
||||
let l = 3;
|
||||
@ -202,7 +200,7 @@ export class SettingsPrimaryPane extends Component<ISettingsPrimaryPaneProps, {
|
||||
}
|
||||
|
||||
let matched = false;
|
||||
const tabs = (items as SettingField[]).map((field) => {
|
||||
const tabs = (items as ISettingField[]).map((field) => {
|
||||
if (this._activeKey === field.name) {
|
||||
matched = true;
|
||||
}
|
||||
@ -235,7 +233,7 @@ export class SettingsPrimaryPane extends Component<ISettingsPrimaryPaneProps, {
|
||||
</Tab.Item>
|
||||
);
|
||||
});
|
||||
const activeKey = matched ? this._activeKey : (items[0] as SettingField).name;
|
||||
const activeKey = matched ? this._activeKey : (items[0] as ISettingField).name;
|
||||
|
||||
const className = classNames('lc-settings-main', {
|
||||
'lc-settings-hide-tabs':
|
||||
@ -261,9 +259,10 @@ export class SettingsPrimaryPane extends Component<ISettingsPrimaryPaneProps, {
|
||||
}
|
||||
}
|
||||
|
||||
function hoverNode(node: Node, flag: boolean) {
|
||||
function hoverNode(node: INode, flag: boolean) {
|
||||
node.hover(flag);
|
||||
}
|
||||
function selectNode(node: Node) {
|
||||
|
||||
function selectNode(node: INode) {
|
||||
node?.select();
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user