Skip to content

Commit

Permalink
Merge pull request #675 from smartxworks/feat/extract-module
Browse files Browse the repository at this point in the history
feat(editor): add extract module feature
  • Loading branch information
tanbowensg authored Jan 19, 2023
2 parents e638b0d + 10bc795 commit 047b8e4
Show file tree
Hide file tree
Showing 33 changed files with 1,454 additions and 135 deletions.
51 changes: 9 additions & 42 deletions packages/editor-sdk/src/components/Widgets/ExpressionWidget.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,11 @@
import React, { useEffect, useMemo, useCallback, useState, useRef } from 'react';
import {
toNumber,
isString,
isNumber,
isBoolean,
isFunction,
isObject,
isUndefined,
isNull,
debounce,
} from 'lodash';
import { toNumber, debounce } from 'lodash';
import { Type, Static } from '@sinclair/typebox';
import { WidgetProps } from '../../types/widget';
import { implementWidget } from '../../utils/widget';
import { ExpressionEditor, ExpressionEditorHandle } from '../Form';
import { isExpression } from '../../utils/validator';
import { getTypeString } from '../../utils/type';
import { getType, getTypeString, Types } from '../../utils/type';
import { ValidateFunction } from 'ajv';
import { ExpressionError } from '@sunmao-ui/runtime';
import { CORE_VERSION, CoreWidgetName, initAjv } from '@sunmao-ui/shared';
Expand All @@ -26,30 +16,6 @@ export function isNumeric(x: string | number) {
}

// highly inspired by appsmith
export enum Types {
STRING = 'STRING',
NUMBER = 'NUMBER',
BOOLEAN = 'BOOLEAN',
OBJECT = 'OBJECT',
ARRAY = 'ARRAY',
FUNCTION = 'FUNCTION',
UNDEFINED = 'UNDEFINED',
NULL = 'NULL',
UNKNOWN = 'UNKNOWN',
}

export const getType = (value: unknown) => {
if (isString(value)) return Types.STRING;
if (isNumber(value)) return Types.NUMBER;
if (isBoolean(value)) return Types.BOOLEAN;
if (Array.isArray(value)) return Types.ARRAY;
if (isFunction(value)) return Types.FUNCTION;
if (isObject(value)) return Types.OBJECT;
if (isUndefined(value)) return Types.UNDEFINED;
if (isNull(value)) return Types.NULL;
return Types.UNKNOWN;
};

function generateTypeDef(
obj: any
): string | Record<string, string | Record<string, unknown>> {
Expand Down Expand Up @@ -164,13 +130,14 @@ export const ExpressionWidget: React.FC<WidgetProps<ExpressionWidgetType>> = pro
const [error, setError] = useState<string | null>(null);
const editorRef = useRef<ExpressionEditorHandle>(null);
const validateFuncRef = useRef<ValidateFunction | null>(null);
const slotTrait = useMemo(
() =>
component.traits.find(trait =>
const slotTrait = useMemo(() => {
if (component.traits) {
return component.traits.find(trait =>
['core/v1/slot', 'core/v2/slot'].includes(trait.type)
),
[component.traits]
);
);
}
return undefined;
}, [component]);
const $slot = useMemo(
() =>
slotTrait
Expand Down
37 changes: 3 additions & 34 deletions packages/editor-sdk/src/components/Widgets/ModuleWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ import { SpecWidget } from './SpecWidget';
import { CORE_VERSION, CoreWidgetName, isJSONSchema } from '@sunmao-ui/shared';
import { css } from '@emotion/css';
import { mapValues } from 'lodash';
import { Type, TSchema } from '@sinclair/typebox';
import type { JSONSchema7 } from 'json-schema';
import { getType, Types } from './ExpressionWidget';
import { json2JsonSchema } from '../../utils/type';

const LabelStyle = css`
font-weight: normal;
Expand All @@ -23,34 +22,6 @@ declare module '../../types/widget' {
}
}

const genSpec = (type: Types, target: any): TSchema => {
switch (type) {
case Types.ARRAY: {
const arrayType = getType(target[0]);
return Type.Array(genSpec(arrayType, target[0]));
}
case Types.OBJECT: {
const objType: Record<string, any> = {};
Object.keys(target).forEach(k => {
const type = getType(target[k]);
objType[k] = genSpec(type, target[k]);
});
return Type.Object(objType);
}
case Types.STRING:
return Type.String();
case Types.NUMBER:
return Type.Number();
case Types.BOOLEAN:
return Type.Boolean();
case Types.NULL:
case Types.UNDEFINED:
return Type.Any();
default:
return Type.Any();
}
};

export const ModuleWidget: React.FC<WidgetProps<ModuleWidgetType>> = props => {
const { component, value, spec, services, path, level, onChange } = props;
const { registry } = services;
Expand Down Expand Up @@ -100,13 +71,11 @@ export const ModuleWidget: React.FC<WidgetProps<ModuleWidgetType>> = props => {
const modulePropertiesSpec = useMemo<JSONSchema7>(() => {
const obj = mapValues(module?.metadata.exampleProperties, p => {
const result = services.stateManager.deepEval(p);
const type = getType(result);
const spec = genSpec(type, result);

return spec;
return json2JsonSchema(result);
});

return Type.Object(obj);
return { type: 'object', properties: obj };
}, [module?.metadata.exampleProperties, services.stateManager]);

return (
Expand Down
2 changes: 1 addition & 1 deletion packages/editor-sdk/src/types/operation.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
type OperationType =
| 'createComponent'
| 'removeComponent'
| 'modifyComponentProperty'
| 'modifyComponentProperties'
| 'modifyComponentId'
| 'adjustComponentOrder'
| 'createTrait'
Expand Down
1 change: 1 addition & 0 deletions packages/editor-sdk/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './widget';
export * from './validator';
export * from './type';
68 changes: 68 additions & 0 deletions packages/editor-sdk/src/utils/type.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
import {
isString,
isNumber,
isBoolean,
isFunction,
isObject,
isUndefined,
isNull,
} from 'lodash';
import type { JSONSchema7 } from 'json-schema';
import { TSchema, Type } from '@sinclair/typebox';

const TypeMap = {
undefined: 'Undefined',
string: 'String',
Expand All @@ -18,3 +30,59 @@ export function getTypeString(value: any) {
return TypeMap[typeof value];
}
}

export enum Types {
STRING = 'STRING',
NUMBER = 'NUMBER',
BOOLEAN = 'BOOLEAN',
OBJECT = 'OBJECT',
ARRAY = 'ARRAY',
FUNCTION = 'FUNCTION',
UNDEFINED = 'UNDEFINED',
NULL = 'NULL',
UNKNOWN = 'UNKNOWN',
}

export const getType = (value: unknown) => {
if (isString(value)) return Types.STRING;
if (isNumber(value)) return Types.NUMBER;
if (isBoolean(value)) return Types.BOOLEAN;
if (Array.isArray(value)) return Types.ARRAY;
if (isFunction(value)) return Types.FUNCTION;
if (isObject(value)) return Types.OBJECT;
if (isUndefined(value)) return Types.UNDEFINED;
if (isNull(value)) return Types.NULL;
return Types.UNKNOWN;
};

const genSpec = (type: Types, target: any): TSchema => {
switch (type) {
case Types.ARRAY: {
const arrayType = getType(target[0]);
return Type.Array(genSpec(arrayType, target[0]));
}
case Types.OBJECT: {
const objType: Record<string, any> = {};
Object.keys(target).forEach(k => {
const type = getType(target[k]);
objType[k] = genSpec(type, target[k]);
});
return Type.Object(objType);
}
case Types.STRING:
return Type.String();
case Types.NUMBER:
return Type.Number();
case Types.BOOLEAN:
return Type.Boolean();
case Types.NULL:
case Types.UNDEFINED:
return Type.Any();
default:
return Type.Any();
}
};
export const json2JsonSchema = (value: any): JSONSchema7 => {
const type = getType(value);
return genSpec(type, value) as JSONSchema7;
};
14 changes: 14 additions & 0 deletions packages/editor/src/AppModel/ComponentModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
} from './IAppModel';
import { TraitModel } from './TraitModel';
import { FieldModel } from './FieldModel';
import { AppModel } from './AppModel';

const SlotTraitType: TraitType = `${CORE_VERSION}/${CoreTraitName.Slot}` as TraitType;
const SlotTraitTypeV2: TraitType = `core/v2/${CoreTraitName.Slot}` as TraitType;
Expand Down Expand Up @@ -304,6 +305,19 @@ export class ComponentModel implements IComponentModel {
this._isDirty = true;
}

removeSlotTrait() {
if (this._slotTrait) {
this.removeTrait(this._slotTrait.id);
}
}

clone() {
return new AppModel(
this.allComponents.map(c => c.toSchema()),
this.registry
).getComponentById(this.id)!;
}

private traverseTree(cb: (c: IComponentModel) => void) {
function traverse(root: IComponentModel) {
cb(root);
Expand Down
2 changes: 2 additions & 0 deletions packages/editor/src/AppModel/IAppModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ export interface IComponentModel {
_isDirty: boolean;
_slotTrait: ITraitModel | null;
toSchema(): ComponentSchema;
clone(): IComponentModel;
updateComponentProperty: (property: string, value: unknown) => void;
// move component from old parent to new parent(or top level if parent is undefined).
appendTo: (parent?: IComponentModel, slot?: SlotName) => void;
Expand All @@ -110,6 +111,7 @@ export interface IComponentModel {
removeTrait: (traitId: TraitId) => void;
updateTraitProperties: (traitId: TraitId, properties: Record<string, unknown>) => void;
updateSlotTrait: (parent: ComponentId, slot: SlotName) => void;
removeSlotTrait: () => void;
removeChild: (child: IComponentModel) => void;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ export const ComponentForm: React.FC<Props> = observer(props => {
onChange={newFormData => {
eventBus.send(
'operation',
genOperation(registry, 'modifyComponentProperty', {
genOperation(registry, 'modifyComponentProperties', {
componentId: selectedComponentId,
properties: newFormData,
})
Expand Down
9 changes: 6 additions & 3 deletions packages/editor/src/components/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,12 @@ export const Editor: React.FC<Props> = observer(
}
}, [isDisplayApp]);
const onPreview = useCallback(() => setPreview(true), []);
const onRightTabChange = useCallback(activatedTab => {
setToolMenuTab(activatedTab);
}, []);
const onRightTabChange = useCallback(
activatedTab => {
setToolMenuTab(activatedTab);
},
[setToolMenuTab]
);

const renderMain = () => {
const appBox = (
Expand Down
1 change: 1 addition & 0 deletions packages/editor/src/components/Explorer/Explorer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export const Explorer: React.FC<Props> = ({ services }) => {
setCurrentVersion={setCurrentVersion}
setCurrentName={setCurrentName}
services={services}
onClose={() => setIsEditingMode(false)}
/>
</ModalBody>
</ModalContent>
Expand Down
Loading

0 comments on commit 047b8e4

Please sign in to comment.