feat: improve lowcode component error state in simulator renderer (#1818)

* feat: improve lowcode component error state in simulator renderer

* chore: use faultComponentMap instead of ComponentRender.FaultComponent
This commit is contained in:
eternalsky 2023-03-31 15:12:39 +08:00 committed by GitHub
parent d0c3c0f13c
commit d64da1e065
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 82 additions and 22 deletions

View File

@ -52,6 +52,8 @@ module.exports = {
'error',
{ default: ['signature', 'field', 'constructor', 'method'] }
],
'@typescript-eslint/no-unused-vars': ['error']
'@typescript-eslint/no-unused-vars': ['error'],
'no-redeclare': 0,
'@typescript-eslint/no-redeclare': 1,
},
};

View File

@ -234,6 +234,10 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
return engineConfig.get('faultComponent') ?? null;
}
get faultComponentMap(): any {
return engineConfig.get('faultComponentMap') ?? null;
}
@computed get componentsAsset(): Asset | undefined {
return this.get('componentsAsset');
}

View File

@ -195,6 +195,7 @@ class Renderer extends Component<{
thisRequiredInJSE={host.thisRequiredInJSE}
notFoundComponent={host.notFoundComponent}
faultComponent={host.faultComponent}
faultComponentMap={host.faultComponentMap}
customCreateElement={(Component: any, props: any, children: any) => {
const { __id, ...viewProps } = props;
viewProps.componentId = __id;

View File

@ -465,6 +465,7 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer {
rendererName: 'LowCodeRenderer',
thisRequiredInJSE: host.thisRequiredInJSE,
faultComponent: host.faultComponent,
faultComponentMap: host.faultComponentMap,
customCreateElement: (Comp: any, props: any, children: any) => {
const componentMeta = host.currentDocument?.getComponentMeta(Comp.displayName);
if (componentMeta?.isModal) {
@ -629,6 +630,7 @@ function getLowCodeComponentProps(props: any) {
}
newProps[k] = props[k];
});
newProps['componentName'] = props['_componentName'];
return newProps;
}

View File

@ -161,7 +161,9 @@ export default function baseRendererFactory(): IBaseRenderComponent {
constructor(props: IBaseRendererProps, context: IBaseRendererContext) {
super(props, context);
this.context = context;
this.__parseExpression = props?.thisRequiredInJSE ? parseThisRequiredExpression : parseExpression;
this.__parseExpression = (str: string, self: any) => {
return parseExpression({ str, self, thisRequired: props?.thisRequiredInJSE, logScope: props.componentName });
};
this.__beforeInit(props);
this.__init(props);
this.__afterInit(props);
@ -299,8 +301,8 @@ export default function baseRendererFactory(): IBaseRenderComponent {
};
__parseData = (data: any, ctx?: Record<string, any>) => {
const { __ctx, thisRequiredInJSE } = this.props;
return parseData(data, ctx || __ctx || this, { thisRequiredInJSE });
const { __ctx, thisRequiredInJSE, componentName } = this.props;
return parseData(data, ctx || __ctx || this, { thisRequiredInJSE, logScope: componentName });
};
__initDataSource = (props: IBaseRendererProps) => {

View File

@ -21,7 +21,7 @@ export default function rendererFactory(): IRenderComponent {
class FaultComponent extends PureComponent<IPublicTypeNodeSchema | any> {
render() {
logger.error(`%c组件渲染异常, 异常原因: ${this.props.error?.message || this.props.error || '未知'}`, 'color: #ff0000;');
logger.error(`%c${this.props.componentName || ''} 组件渲染异常, 异常原因: ${this.props.error?.message || this.props.error || '未知'}`, 'color: #ff0000;');
return createElement(Div, {
style: {
width: '100%',
@ -159,7 +159,25 @@ export default function rendererFactory(): IRenderComponent {
}
getFaultComponent() {
return this.props.faultComponent || FaultComponent;
const { faultComponent, faultComponentMap, schema } = this.props;
if (faultComponentMap) {
const { componentName } = schema;
return faultComponentMap[componentName] || faultComponent || FaultComponent;
}
return faultComponent || FaultComponent;
}
getComp() {
const { schema, components } = this.props;
const { componentName } = schema;
const allComponents = { ...RENDERER_COMPS, ...components };
let Comp = allComponents[componentName] || RENDERER_COMPS[`${componentName}Renderer`];
if (Comp && Comp.prototype) {
if (!(Comp.prototype instanceof BaseRenderer)) {
Comp = RENDERER_COMPS[`${componentName}Renderer`];
}
}
return Comp;
}
render() {
@ -173,14 +191,8 @@ export default function rendererFactory(): IRenderComponent {
return '模型结构异常';
}
debug('entry.render');
const { componentName } = schema;
const allComponents = { ...RENDERER_COMPS, ...components };
let Comp = allComponents[componentName] || RENDERER_COMPS[`${componentName}Renderer`];
if (Comp && Comp.prototype) {
if (!(Comp.prototype instanceof BaseRenderer)) {
Comp = RENDERER_COMPS[`${componentName}Renderer`];
}
}
let Comp = this.getComp();
if (this.state && this.state.engineRenderError) {
return createElement(this.getFaultComponent(), {
@ -190,11 +202,13 @@ export default function rendererFactory(): IRenderComponent {
}
if (Comp) {
return createElement(AppContext.Provider, { value: {
appHelper,
components: allComponents,
engine: this,
} }, createElement(ConfigProvider, {
return createElement(AppContext.Provider, {
value: {
appHelper,
components: allComponents,
engine: this,
},
}, createElement(ConfigProvider, {
device: this.props.device,
locale: this.props.locale,
}, createElement(Comp, {

View File

@ -160,6 +160,11 @@ export interface IRendererProps {
/** 当组件渲染异常时,显示的组件 */
faultComponent?: IGeneralComponent;
/** */
faultComponentMap?: {
[prop: string]: IGeneralComponent;
};
/** 设备信息 */
device?: string;
@ -208,6 +213,7 @@ export interface IBaseRendererProps {
* 'default'
*/
device?: 'default' | 'mobile' | string;
componentName?: string;
}
export interface INodeInfo {

View File

@ -157,6 +157,7 @@ export function canAcceptsRef(Comp: any) {
// eslint-disable-next-line max-len
return Comp?.$$typeof === REACT_FORWARD_REF_TYPE || Comp?.prototype?.isReactComponent || Comp?.prototype?.setState || Comp._forwardRef;
}
/**
* transform array to a object
* @param arr array to be transformed
@ -207,7 +208,6 @@ export function checkPropTypes(value: any, name: string, rule: any, componentNam
return !err;
}
/**
* transform string to a function
* @param str function in string form
@ -230,7 +230,26 @@ export function transformStringToFunction(str: string) {
* @param self scope object
* @returns funtion
*/
export function parseExpression(str: any, self: any, thisRequired = false) {
function parseExpression(options: {
str: any; self: any; thisRequired?: boolean; logScope?: string;
}): any;
function parseExpression(str: any, self: any, thisRequired?: boolean): any;
function parseExpression(a: any, b?: any, c = false) {
let str;
let self;
let thisRequired;
let logScope;
if (typeof a === 'object' && b === undefined) {
str = a.str;
self = a.self;
thisRequired = a.thisRequired;
logScope = a.logScope;
} else {
str = a;
self = b;
thisRequired = c;
}
try {
const contextArr = ['"use strict";', 'var __self = arguments[0];'];
contextArr.push('return ');
@ -250,11 +269,15 @@ export function parseExpression(str: any, self: any, thisRequired = false) {
const code = `with(${thisRequired ? '{}' : '$scope || {}'}) { ${tarStr} }`;
return new Function('$scope', code)(self);
} catch (err) {
logger.error('parseExpression.error', err, str, self?.__self ?? self);
logger.error(`${logScope || ''} parseExpression.error`, err, str, self?.__self ?? self);
return undefined;
}
}
export {
parseExpression,
};
export function parseThisRequiredExpression(str: any, self: any) {
return parseExpression(str, self, true);
}
@ -320,11 +343,17 @@ export function forEach(targetObj: any, fn: any, context?: any) {
interface IParseOptions {
thisRequiredInJSE?: boolean;
logScope?: string;
}
export function parseData(schema: unknown, self: any, options: IParseOptions = {}): any {
if (isJSExpression(schema)) {
return parseExpression(schema, self, options.thisRequiredInJSE);
return parseExpression({
str: schema,
self,
thisRequired: options.thisRequiredInJSE,
logScope: options.logScope,
});
} else if (isI18nData(schema)) {
return parseI18n(schema, self);
} else if (typeof schema === 'string') {