forked from shesha-io/shesha-framework
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsettingsControl.tsx
More file actions
137 lines (118 loc) · 5.39 KB
/
settingsControl.tsx
File metadata and controls
137 lines (118 loc) · 5.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
import React, { ReactElement, useEffect } from 'react';
import { getPropertySettingsFromValue } from './utils';
import { CodeEditor, IPropertySetting, PropertySettingMode } from '@/index';
import { useStyles } from './styles/styles';
import { isEqual } from 'lodash';
import { ICodeExposedVariable } from '@/components/codeVariablesTable';
import camelcase from 'camelcase';
import { GetAvailableConstantsFunc, GetResultTypeFunc, ICodeEditorProps } from '../codeEditor/interfaces';
import { CodeEditorWithStandardConstants } from '../codeEditor/codeEditorWithConstants';
import { useConstantsEvaluator } from '../codeEditor/hooks/useConstantsEvaluator';
import { useResultTypeEvaluator } from '../codeEditor/hooks/useResultType';
import { Button } from 'antd';
import {
CodeOutlined, CodeFilled, FormOutlined
} from '@ant-design/icons';
export type SettingsControlChildrenType = (value: any, onChange: (val: any) => void, propertyName: string) => ReactElement;
export interface ISettingsControlProps<Value = any> {
propertyName: string;
readOnly?: boolean;
value?: IPropertySetting<Value>;
setHasCode?: (hasCode: boolean) => void;
hasCode?: boolean;
mode: PropertySettingMode;
onChange?: (value: IPropertySetting<Value>) => void;
readonly children?: SettingsControlChildrenType;
availableConstantsExpression?: string | GetAvailableConstantsFunc;
resultTypeExpression?: string | GetResultTypeFunc;
useAsyncEvaluation?: boolean;
}
export const defaultExposedVariables: ICodeExposedVariable[] = [
{ name: "data", description: "Selected form values", type: "object" },
{ name: "pageContext", description: "Contexts data of current page", type: "object" },
{ name: "contexts", description: "Contexts data", type: "object" },
{ name: "globalState", description: "Global state", type: "object" },
{ name: "setGlobalState", description: "Functiont to set globalState", type: "function" },
{ name: "formMode", description: "Form mode", type: "'designer' | 'edit' | 'readonly'" },
{ name: "form", description: "Form instance", type: "object" },
{ name: "selectedRow", description: "Selected row of nearest table (null if not available)", type: "object" },
{ name: "moment", description: "moment", type: "object" },
{ name: "http", description: "axiosHttp", type: "object" },
{ name: "message", description: "message framework", type: "object" },
];
export const SettingsControl = <Value = any>(props: ISettingsControlProps<Value>) => {
const constantsEvaluator = useConstantsEvaluator({ availableConstantsExpression: props.availableConstantsExpression });
const resultType = useResultTypeEvaluator({ resultTypeExpression: props.resultTypeExpression });
const setting = getPropertySettingsFromValue(props.value);
const { _mode: mode, _code: code } = setting;
const { styles } = useStyles(setting._code);
const onInternalChange = (value: IPropertySetting, m?: PropertySettingMode) => {
const newSetting = { ...value, _mode: (m ?? mode) };
const newValue = !!newSetting._code || newSetting._mode === 'code' ? newSetting : value._value;
if (props.onChange)
props.onChange(newValue);
};
useEffect(() => {
const newMode = !!code ? 'code' : 'value' as IPropertySetting<Value>['_mode'];
props.setHasCode?.(newMode === 'code');
onInternalChange({ ...setting, _mode: newMode }, newMode);
}, [code]);
const codeOnChange = (val: any) => {
const newValue = { ...setting, _code: val };
onInternalChange(newValue);
};
const valueOnChange = (val: any) => {
if (!isEqual(setting?._value, val)) {
const newValue = { ...setting, _value: val };
onInternalChange(newValue);
}
};
const onSwitchMode = () => {
const newMode = mode === 'code' ? 'value' : 'code';
onInternalChange(setting, newMode);
};
const propertyName = !!setting._code || setting._mode === 'code' ? `${props.propertyName}._value` : props.propertyName;
const functionName = `get${camelcase(props.propertyName, { pascalCase: true })}`;
const codeEditorProps: ICodeEditorProps = {
readOnly: props.readOnly,
value: setting._code,
onChange: codeOnChange,
mode: 'dialog',
language: 'typescript',
propertyName: props.propertyName + 'Code',
fileName: props.propertyName,
wrapInTemplate: true,
templateSettings: {
functionName: functionName,
useAsyncDeclaration: props.useAsyncEvaluation,
},
type: 'text',
label: ' ',
ghost: true,
exposedVariables: defaultExposedVariables,
hidden: !setting._code && props.readOnly,
};
const editor = constantsEvaluator
? <CodeEditor {...codeEditorProps} availableConstants={constantsEvaluator} resultType={resultType} />
: <CodeEditorWithStandardConstants {...codeEditorProps} resultType={resultType} />;
return (
<div className={mode === 'code' ? styles.contentCode : styles.contentJs}>
<Button
hidden={props.readOnly}
className={`${styles.jsSwitch} inlineJS`}
type='text'
danger={mode === 'value' && !!code}
ghost
size='small'
icon={mode === 'code' ? <FormOutlined /> : !!code ? <CodeFilled /> : <CodeOutlined />}
color='lightslategrey'
onClick={onSwitchMode}
/>
{mode === 'code' && editor}
{mode === 'value' && <div className={styles.jsContent} style={{ marginLeft: 0 }}>
{props.children(setting?._value, valueOnChange, propertyName)}
</div>}
</div>
);
};
export default SettingsControl;