fix: remove console.log statements, update test, and purge children in NodeChildren class

This commit is contained in:
liujuping 2024-03-06 16:38:19 +08:00 committed by 林熠
parent d7dfde5452
commit 71f9e08cb2
9 changed files with 77 additions and 105 deletions

View File

@ -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})/`,
],

View File

@ -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;

View File

@ -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;
}

View File

@ -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)) {

View File

@ -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() {

View File

@ -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);

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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();
}