mirror of
https://gitee.com/baidu/amis.git
synced 2024-11-30 02:48:55 +08:00
feat: amis 添加更多扩展功能 (#10924)
This commit is contained in:
parent
e0460bf080
commit
cb5e5dca5e
@ -14,6 +14,14 @@ import {render as renderAmis, makeTranslator} from 'amis-core';
|
||||
import 'amis/lib/minimal';
|
||||
|
||||
import 'amis-ui/lib/locale/en-US';
|
||||
import 'amis-ui/lib/locale/zh-CN';
|
||||
import 'amis-ui/lib/locale/en-US';
|
||||
import 'amis-ui/lib/locale/de-DE';
|
||||
import 'amis-ui/lib/themes/cxd';
|
||||
import 'amis-ui/lib/themes/ang';
|
||||
import 'amis-ui/lib/themes/antd';
|
||||
import 'amis-ui/lib/themes/dark';
|
||||
|
||||
import 'history';
|
||||
import {attachmentAdpator} from 'amis-core';
|
||||
import {pdfUrlLoad} from './loadPdfjsWorker';
|
||||
|
@ -55,3 +55,10 @@ global.afterAll(() => {
|
||||
console.error = originalError;
|
||||
cleanup();
|
||||
});
|
||||
|
||||
// expect.addSnapshotSerializer({
|
||||
// test: val => typeof val === 'string' && /^[a-z0-9]{12}$/.test(val),
|
||||
// print: val => {
|
||||
// return JSON.stringify('__guid_dynamic_value__');
|
||||
// }
|
||||
// });
|
||||
|
@ -7,9 +7,8 @@
|
||||
import React from 'react';
|
||||
import {findDOMNode} from 'react-dom';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
import {autobind, camel, preventDefault} from '../utils';
|
||||
import {autobind, camel, preventDefault, TestIdBuilder} from '../utils';
|
||||
import {SubPopoverDisplayedID} from './Overlay';
|
||||
import type {TestIdBuilder} from 'amis-core';
|
||||
|
||||
export interface Offset {
|
||||
x: number;
|
||||
|
@ -195,7 +195,8 @@ function rendererToComponent(
|
||||
export function registerRenderer(config: RendererConfig): RendererConfig {
|
||||
if (!config.test && !config.type) {
|
||||
throw new TypeError('please set config.type or config.test');
|
||||
} else if (!config.type) {
|
||||
} else if (!config.type && config.name !== 'static') {
|
||||
// todo static 目前还没办法不用 test 来实现
|
||||
console.warn(
|
||||
`config.type is recommended for register renderer(${config.test})`
|
||||
);
|
||||
|
@ -39,7 +39,7 @@ export * from './store';
|
||||
import * as utils from './utils/helper';
|
||||
import {getEnv} from 'mobx-state-tree';
|
||||
|
||||
import {RegisterStore, RendererStore} from './store';
|
||||
import {RegisterStore, registerStore, RendererStore} from './store';
|
||||
import type {IColumn, IColumn2, IRow, IRow2} from './store';
|
||||
import {
|
||||
setDefaultLocale,
|
||||
@ -133,6 +133,7 @@ export {
|
||||
RendererEnv,
|
||||
EnvContext,
|
||||
RegisterStore,
|
||||
registerStore,
|
||||
FormItem,
|
||||
FormItemWrap,
|
||||
FormItemProps,
|
||||
|
@ -114,6 +114,7 @@ export {iRendererStore, IIRendererStore};
|
||||
export const RegisterStore = function (store: any) {
|
||||
allowedStoreList.push(store as any);
|
||||
};
|
||||
export const registerStore = RegisterStore;
|
||||
|
||||
export {
|
||||
ServiceStore,
|
||||
|
@ -216,6 +216,18 @@ export type ClassName =
|
||||
[propName: string]: boolean | undefined | null | string;
|
||||
};
|
||||
|
||||
export type RequestAdaptor = (
|
||||
api: ApiObject,
|
||||
context: any
|
||||
) => ApiObject | Promise<ApiObject>;
|
||||
|
||||
export type ResponseAdaptor = (
|
||||
payload: object,
|
||||
response: fetcherResult,
|
||||
api: ApiObject,
|
||||
context: any
|
||||
) => any;
|
||||
|
||||
export interface ApiObject extends BaseApiObject {
|
||||
config?: {
|
||||
withCredentials?: boolean;
|
||||
@ -228,16 +240,8 @@ export interface ApiObject extends BaseApiObject {
|
||||
body?: PlainObject;
|
||||
query?: PlainObject;
|
||||
mockResponse?: PlainObject;
|
||||
adaptor?: (
|
||||
payload: object,
|
||||
response: fetcherResult,
|
||||
api: ApiObject,
|
||||
context: any
|
||||
) => any;
|
||||
requestAdaptor?: (
|
||||
api: ApiObject,
|
||||
context: any
|
||||
) => ApiObject | Promise<ApiObject>;
|
||||
adaptor?: ResponseAdaptor;
|
||||
requestAdaptor?: RequestAdaptor;
|
||||
/**
|
||||
* api 发送上下文,可以用来传递一些数据给 api 的 adaptor
|
||||
* @readonly
|
||||
|
@ -1,5 +1,13 @@
|
||||
import omit from 'lodash/omit';
|
||||
import {Api, ApiObject, EventTrack, fetcherResult, Payload} from '../types';
|
||||
import {
|
||||
Api,
|
||||
ApiObject,
|
||||
EventTrack,
|
||||
fetcherResult,
|
||||
Payload,
|
||||
RequestAdaptor,
|
||||
ResponseAdaptor
|
||||
} from '../types';
|
||||
import {FetcherConfig} from '../factory';
|
||||
import {tokenize, dataMapping, escapeHtml} from './tpl-builtin';
|
||||
import {evalExpression} from './tpl';
|
||||
@ -33,6 +41,44 @@ interface ApiCacheConfig extends ApiObject {
|
||||
}
|
||||
|
||||
const apiCaches: Array<ApiCacheConfig> = [];
|
||||
const requestAdaptors: Array<RequestAdaptor> = [];
|
||||
const responseAdaptors: Array<ResponseAdaptor> = [];
|
||||
|
||||
/**
|
||||
* 添加全局发送适配器
|
||||
* @param adaptor
|
||||
*/
|
||||
export function addApiRequestAdaptor(adaptor: RequestAdaptor) {
|
||||
requestAdaptors.push(adaptor);
|
||||
return () => removeApiRequestAdaptor(adaptor);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除全局发送适配器
|
||||
* @param adaptor
|
||||
*/
|
||||
export function removeApiRequestAdaptor(adaptor: RequestAdaptor) {
|
||||
const idx = requestAdaptors.findIndex(i => i === adaptor);
|
||||
~idx && requestAdaptors.splice(idx, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加全局响应适配器
|
||||
* @param adaptor
|
||||
*/
|
||||
export function addApiResponseAdator(adaptor: ResponseAdaptor) {
|
||||
responseAdaptors.push(adaptor);
|
||||
return () => removeApiResponseAdaptor(adaptor);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除全局响应适配器
|
||||
* @param adaptor
|
||||
*/
|
||||
export function removeApiResponseAdaptor(adaptor: ResponseAdaptor) {
|
||||
const idx = responseAdaptors.findIndex(i => i === adaptor);
|
||||
~idx && responseAdaptors.splice(idx, 1);
|
||||
}
|
||||
|
||||
const isIE = !!(document as any).documentMode;
|
||||
|
||||
@ -488,25 +534,40 @@ export function wrapFetcher(
|
||||
api = buildApi(api, data, options) as ApiObject;
|
||||
(api as ApiObject).context = data;
|
||||
|
||||
const adaptors = requestAdaptors.concat();
|
||||
if (api.requestAdaptor) {
|
||||
debug('api', 'before requestAdaptor', api);
|
||||
const originQuery = api.query;
|
||||
const originQueryCopy = isPlainObject(api.query)
|
||||
? cloneDeep(api.query)
|
||||
: api.query;
|
||||
api = (await api.requestAdaptor(api, data)) || api;
|
||||
const adaptor = api.requestAdaptor;
|
||||
adaptors.unshift(async (api: ApiObject, context) => {
|
||||
const originQuery = api.query;
|
||||
const originQueryCopy = isPlainObject(api.query)
|
||||
? cloneDeep(api.query)
|
||||
: api.query;
|
||||
|
||||
if (
|
||||
api.query !== originQuery ||
|
||||
(isPlainObject(api.query) && !isEqual(api.query, originQueryCopy))
|
||||
) {
|
||||
// 如果 api.data 有变化,且是 get 请求,那么需要重新构建 url
|
||||
const idx = api.url.indexOf('?');
|
||||
api.url = `${~idx ? api.url.substring(0, idx) : api.url}?${qsstringify(
|
||||
api.query
|
||||
)}`;
|
||||
}
|
||||
debug('api', 'after requestAdaptor', api);
|
||||
debug('api', 'before requestAdaptor', api);
|
||||
api = (await adaptor.call(api, api, context)) || api;
|
||||
|
||||
if (
|
||||
api.query !== originQuery ||
|
||||
(isPlainObject(api.query) && !isEqual(api.query, originQueryCopy))
|
||||
) {
|
||||
// 如果 api.data 有变化,且是 get 请求,那么需要重新构建 url
|
||||
const idx = api.url.indexOf('?');
|
||||
api.url = `${
|
||||
~idx ? api.url.substring(0, idx) : api.url
|
||||
}?${qsstringify(api.query)}`;
|
||||
}
|
||||
debug('api', 'after requestAdaptor', api);
|
||||
return api;
|
||||
});
|
||||
}
|
||||
|
||||
// 执行所有的发送适配器
|
||||
if (adaptors.length) {
|
||||
api = await adaptors.reduce(async (api, fn) => {
|
||||
let ret: any = await api;
|
||||
ret = (await fn(ret, data)) || ret;
|
||||
return ret as ApiObject;
|
||||
}, Promise.resolve(api));
|
||||
}
|
||||
|
||||
if (
|
||||
@ -589,31 +650,50 @@ export function wrapFetcher(
|
||||
return wrappedFetcher;
|
||||
}
|
||||
|
||||
export function wrapAdaptor(
|
||||
export async function wrapAdaptor(
|
||||
promise: Promise<fetcherResult>,
|
||||
api: ApiObject,
|
||||
context: any
|
||||
) {
|
||||
const adaptor = api.adaptor;
|
||||
return adaptor
|
||||
? promise
|
||||
.then(async response => {
|
||||
debug('api', 'before adaptor data', (response as any).data);
|
||||
let result = adaptor((response as any).data, response, api, context);
|
||||
const adaptors = responseAdaptors.concat();
|
||||
if (api.adaptor) {
|
||||
const adaptor = api.adaptor;
|
||||
adaptors.push(
|
||||
async (
|
||||
payload: object,
|
||||
response: fetcherResult,
|
||||
api: ApiObject,
|
||||
context: any
|
||||
) => {
|
||||
debug('api', 'before adaptor data', (response as any).data);
|
||||
let result = adaptor((response as any).data, response, api, context);
|
||||
|
||||
if (result?.then) {
|
||||
result = await result;
|
||||
}
|
||||
if (result?.then) {
|
||||
result = await result;
|
||||
}
|
||||
|
||||
debug('api', 'after adaptor data', result);
|
||||
debug('api', 'after adaptor data', result);
|
||||
return result;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
...response,
|
||||
data: result
|
||||
};
|
||||
})
|
||||
.then(ret => responseAdaptor(ret, api))
|
||||
: promise.then(ret => responseAdaptor(ret, api));
|
||||
const response = await adaptors.reduce(async (promise, adaptor) => {
|
||||
let response: any = await promise;
|
||||
let result =
|
||||
adaptor(response.data, response, api, context) ?? response.data;
|
||||
|
||||
if (result?.then) {
|
||||
result = await result;
|
||||
}
|
||||
|
||||
return {
|
||||
...response,
|
||||
data: result
|
||||
} as fetcherResult;
|
||||
}, promise);
|
||||
|
||||
return responseAdaptor(response, api);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -30,7 +30,7 @@ const external = id =>
|
||||
|
||||
export default [
|
||||
{
|
||||
input: ['./src/index.ts', './src/doc.ts'],
|
||||
input: ['./src/index.ts'],
|
||||
output: [
|
||||
{
|
||||
...settings,
|
||||
@ -45,7 +45,7 @@ export default [
|
||||
plugins: getPlugins('cjs')
|
||||
},
|
||||
{
|
||||
input: ['./src/index.ts', './src/doc.ts'],
|
||||
input: ['./src/index.ts'],
|
||||
output: [
|
||||
{
|
||||
...settings,
|
||||
@ -61,6 +61,23 @@ export default [
|
||||
}
|
||||
];
|
||||
|
||||
function transpileDynamicImportForCJS(options) {
|
||||
return {
|
||||
name: 'transpile-dynamic-import-for-cjs',
|
||||
renderDynamicImport({format, targetModuleId}) {
|
||||
if (format !== 'cjs') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
left: 'Promise.resolve().then(function() {return new Promise(function(fullfill) {require([',
|
||||
right:
|
||||
', "tslib"], function(mod, tslib) {fullfill(tslib.__importStar(mod))})})})'
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function getPlugins(format = 'esm') {
|
||||
const typeScriptOptions = {
|
||||
typescript: require('typescript'),
|
||||
@ -83,6 +100,7 @@ function getPlugins(format = 'esm') {
|
||||
};
|
||||
|
||||
return [
|
||||
transpileDynamicImportForCJS(),
|
||||
json(),
|
||||
resolve({
|
||||
jsnext: true,
|
||||
|
@ -89,26 +89,14 @@ async function main(...params: Array<any>) {
|
||||
|
||||
fs.writeFileSync(
|
||||
outputFile,
|
||||
`/**\n * 公式文档 请运行 \`npm run genDoc\` 自动生成\n */\nexport const doc: ${[
|
||||
`{`,
|
||||
` name: string;`,
|
||||
` description: string;`,
|
||||
` example: string;`,
|
||||
` params: {`,
|
||||
` type: string;`,
|
||||
` name: string;`,
|
||||
` description: string | null;`,
|
||||
` }[];`,
|
||||
` returns: {`,
|
||||
` type: string;`,
|
||||
` description: string | null;`,
|
||||
` };`,
|
||||
` namespace: string;`,
|
||||
`}[]`
|
||||
].join('\n')} = ${JSON.stringify(result, null, 2).replace(
|
||||
`/**\n * 公式文档 请运行 \`npm run genDoc\` 自动生成\n */\n
|
||||
import {bulkRegisterFunctionDoc} from './function';
|
||||
|
||||
bulkRegisterFunctionDoc(${JSON.stringify(result, null, 2).replace(
|
||||
/\"(\w+)\"\:/g,
|
||||
(_, key) => `${key}:`
|
||||
)};`,
|
||||
)});
|
||||
`,
|
||||
'utf8'
|
||||
);
|
||||
console.log(`公式文档生成 > ${outputFile}`);
|
||||
|
@ -1,21 +1,10 @@
|
||||
/**
|
||||
* 公式文档 请运行 `npm run genDoc` 自动生成
|
||||
*/
|
||||
export const doc: {
|
||||
name: string;
|
||||
description: string;
|
||||
example: string;
|
||||
params: {
|
||||
type: string;
|
||||
name: string;
|
||||
description: string | null;
|
||||
}[];
|
||||
returns: {
|
||||
type: string;
|
||||
description: string | null;
|
||||
};
|
||||
namespace: string;
|
||||
}[] = [
|
||||
|
||||
import {bulkRegisterFunctionDoc} from './function';
|
||||
|
||||
bulkRegisterFunctionDoc([
|
||||
{
|
||||
name: 'IF',
|
||||
description:
|
||||
@ -1982,4 +1971,4 @@ export const doc: {
|
||||
},
|
||||
namespace: '其他'
|
||||
}
|
||||
];
|
||||
]);
|
||||
|
@ -26,14 +26,14 @@ export class Evaluator {
|
||||
contextStack: Array<(varname: string) => any> = [];
|
||||
|
||||
static defaultFilters: FilterMap = {};
|
||||
static setDefaultFilters(filters: FilterMap) {
|
||||
static extendDefaultFilters(filters: FilterMap) {
|
||||
Evaluator.defaultFilters = {
|
||||
...Evaluator.defaultFilters,
|
||||
...filters
|
||||
};
|
||||
}
|
||||
static defaultFunctions: FunctionMap = {};
|
||||
static setDefaultFunctions(funtions: FunctionMap) {
|
||||
static extendDefaultFunctions(funtions: FunctionMap) {
|
||||
Evaluator.defaultFunctions = {
|
||||
...Evaluator.defaultFunctions,
|
||||
...funtions
|
||||
@ -2385,6 +2385,10 @@ export class Evaluator {
|
||||
}
|
||||
}
|
||||
|
||||
// 兼容
|
||||
(Evaluator as any).setDefaultFilters = Evaluator.extendDefaultFilters;
|
||||
(Evaluator as any).setDefaultFunctions = Evaluator.extendDefaultFunctions;
|
||||
|
||||
export function getCookie(name: string) {
|
||||
const value = `; ${document.cookie}`;
|
||||
const parts = value.split(`; ${name}=`);
|
||||
|
@ -33,12 +33,12 @@ export function registerFilter(
|
||||
fn: (input: any, ...args: any[]) => any
|
||||
): void {
|
||||
filters[name] = fn;
|
||||
Evaluator.setDefaultFilters(filters);
|
||||
Evaluator.extendDefaultFilters(filters);
|
||||
}
|
||||
|
||||
export function extendsFilters(value: FilterMap) {
|
||||
Object.assign(filters, value);
|
||||
Evaluator.setDefaultFilters(filters);
|
||||
Evaluator.extendDefaultFilters(filters);
|
||||
}
|
||||
|
||||
export function getFilters() {
|
||||
|
@ -1,17 +1,16 @@
|
||||
import {Evaluator} from './evalutor';
|
||||
import {FunctionMap, FunctionDocMap, FunctionDocItem} from './types';
|
||||
|
||||
export const functions: FunctionMap = {};
|
||||
import {FunctionDocMap, FunctionDocItem} from './types';
|
||||
|
||||
export function registerFunction(
|
||||
name: string,
|
||||
fn: (input: any, ...args: any[]) => any
|
||||
fn: (this: Evaluator, ...args: Array<any>) => any
|
||||
): void {
|
||||
functions[`fn${name}`] = fn;
|
||||
Evaluator.setDefaultFunctions(functions);
|
||||
Evaluator.extendDefaultFunctions({
|
||||
[`fn${name}`]: fn
|
||||
});
|
||||
}
|
||||
|
||||
export let functionDocs: FunctionDocMap = {};
|
||||
export const functionDocs: FunctionDocMap = {};
|
||||
|
||||
export function registerFunctionDoc(groupName: string, item: FunctionDocItem) {
|
||||
if (functionDocs[groupName]) {
|
||||
@ -20,3 +19,38 @@ export function registerFunctionDoc(groupName: string, item: FunctionDocItem) {
|
||||
functionDocs[groupName] = [item];
|
||||
}
|
||||
}
|
||||
|
||||
export function bulkRegisterFunctionDoc(
|
||||
fnDocs: {
|
||||
name: string;
|
||||
description: string;
|
||||
example: string;
|
||||
params: {
|
||||
type: string;
|
||||
name: string;
|
||||
description: string | null;
|
||||
}[];
|
||||
returns: {
|
||||
type: string;
|
||||
description: string | null;
|
||||
};
|
||||
namespace: string;
|
||||
}[]
|
||||
) {
|
||||
fnDocs.forEach(item => registerFunctionDoc(item.namespace || 'Others', item));
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册公式,并同时注册公式说明
|
||||
* @param name
|
||||
* @param fn
|
||||
* @param fnInfo
|
||||
*/
|
||||
export function registerFormula(
|
||||
name: string,
|
||||
fn: (this: Evaluator, ...args: Array<any>) => any,
|
||||
fnInfo?: FunctionDocItem
|
||||
) {
|
||||
registerFunction(name, fn);
|
||||
fnInfo && registerFunctionDoc(fnInfo.namespace || 'Others', fnInfo);
|
||||
}
|
||||
|
@ -3,7 +3,12 @@ import {AsyncEvaluator} from './evalutorForAsync';
|
||||
import {parse} from './parser';
|
||||
import {lexer} from './lexer';
|
||||
import {registerFilter, filters, getFilters, extendsFilters} from './filter';
|
||||
import {registerFunction, registerFunctionDoc, functionDocs} from './function';
|
||||
import {
|
||||
registerFunction,
|
||||
registerFunctionDoc,
|
||||
functionDocs,
|
||||
registerFormula
|
||||
} from './function';
|
||||
import type {
|
||||
FilterContext,
|
||||
ASTNode,
|
||||
@ -19,9 +24,9 @@ export {
|
||||
filters,
|
||||
getFilters,
|
||||
registerFilter,
|
||||
registerFormula,
|
||||
registerFunction,
|
||||
registerFunctionDoc,
|
||||
functionDocs,
|
||||
extendsFilters
|
||||
};
|
||||
|
||||
@ -53,5 +58,14 @@ export async function evaluateForAsync(
|
||||
return new AsyncEvaluator(data, options).evalute(ast);
|
||||
}
|
||||
|
||||
Evaluator.setDefaultFilters(getFilters());
|
||||
Evaluator.extendDefaultFilters(getFilters());
|
||||
AsyncEvaluator.setDefaultFilters(getFilters());
|
||||
|
||||
export async function getFunctionsDoc() {
|
||||
await import('./doc');
|
||||
|
||||
return Object.entries(functionDocs).map(([k, items]) => ({
|
||||
groupName: k,
|
||||
items
|
||||
}));
|
||||
}
|
||||
|
@ -5,13 +5,14 @@ export interface FilterMap {
|
||||
}
|
||||
|
||||
export interface FunctionMap {
|
||||
[propName: string]: (this: Evaluator, ast: Object, data: any) => any;
|
||||
[propName: string]: (this: Evaluator, ...args: Array<any>) => any;
|
||||
}
|
||||
|
||||
export interface FunctionDocItem {
|
||||
name: string; // 函数名
|
||||
example?: string; // 示例
|
||||
description?: string; // 描述
|
||||
namespace?: string;
|
||||
[propName: string]: any;
|
||||
}
|
||||
export interface FunctionDocMap {
|
||||
|
3
packages/amis-ui/src/components/Menu.tsx
Normal file
3
packages/amis-ui/src/components/Menu.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
import Menu from './menu/index';
|
||||
|
||||
export default Menu;
|
3
packages/amis-ui/src/components/Table.tsx
Normal file
3
packages/amis-ui/src/components/Table.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
import Table from './table/index';
|
||||
|
||||
export default Table;
|
@ -15,15 +15,13 @@ import {
|
||||
localeable,
|
||||
LocaleProps
|
||||
} from 'amis-core';
|
||||
import type {FunctionDocMap} from 'amis-formula/lib/types';
|
||||
|
||||
import {editorFactory} from './plugin';
|
||||
import FuncList from './FuncList';
|
||||
import VariableList from './VariableList';
|
||||
import {toast} from '../Toast';
|
||||
import Switch from '../Switch';
|
||||
import CodeEditor, {FuncGroup, FuncItem, VariableItem} from './CodeEditor';
|
||||
import {functionDocs} from 'amis-formula';
|
||||
import {getFunctionsDoc} from 'amis-formula';
|
||||
import Transition, {
|
||||
EXITED,
|
||||
ENTERING,
|
||||
@ -130,49 +128,13 @@ export class FormulaEditor extends React.Component<
|
||||
unmounted: boolean = false;
|
||||
editor = React.createRef<any>();
|
||||
|
||||
static buildDefaultFunctions(
|
||||
doc: Array<{
|
||||
namespace: string;
|
||||
name: string;
|
||||
[propName: string]: any;
|
||||
}>
|
||||
) {
|
||||
const funcs: Array<FuncGroup> = [];
|
||||
|
||||
doc.forEach(item => {
|
||||
const namespace = item.namespace || 'Others';
|
||||
let exists = funcs.find(item => item.groupName === namespace);
|
||||
if (!exists) {
|
||||
exists = {
|
||||
groupName: namespace,
|
||||
items: []
|
||||
};
|
||||
funcs.push(exists);
|
||||
}
|
||||
exists.items.push(item);
|
||||
});
|
||||
|
||||
return funcs;
|
||||
}
|
||||
|
||||
static buildCustomFunctions(map: FunctionDocMap = {}) {
|
||||
return Object.entries(map).map(([k, items]) => ({
|
||||
groupName: k,
|
||||
items
|
||||
}));
|
||||
}
|
||||
|
||||
static async buildFunctions(
|
||||
functions?: Array<any>,
|
||||
functionsFilter?: (functions: Array<FuncGroup>) => Array<FuncGroup>
|
||||
): Promise<any> {
|
||||
const {doc} = await import('amis-formula/lib/doc');
|
||||
const builtInFunctions = await getFunctionsDoc();
|
||||
const customFunctions = Array.isArray(functions) ? functions : [];
|
||||
const functionList = [
|
||||
...FormulaEditor.buildDefaultFunctions(doc),
|
||||
...FormulaEditor.buildCustomFunctions(functionDocs),
|
||||
...customFunctions
|
||||
];
|
||||
const functionList = [...builtInFunctions, ...customFunctions];
|
||||
|
||||
if (functionsFilter) {
|
||||
return functionsFilter(functionList);
|
||||
|
@ -24,7 +24,6 @@ import Modal from '../Modal';
|
||||
import PopUp from '../PopUp';
|
||||
import FormulaInput from './Input';
|
||||
import {FuncGroup, VariableItem} from './CodeEditor';
|
||||
import {functionDocs} from 'amis-formula';
|
||||
|
||||
export const InputSchemaType = [
|
||||
'text',
|
||||
|
@ -70,7 +70,7 @@ import TableSelection from './TableSelection';
|
||||
import TreeSelection from './TreeSelection';
|
||||
import AssociatedSelection from './AssociatedSelection';
|
||||
import PullRefresh from './PullRefresh';
|
||||
import Table from './table';
|
||||
import Table from './Table';
|
||||
import SchemaVariableListPicker from './schema-editor/SchemaVariableListPicker';
|
||||
import SchemaVariableList from './schema-editor/SchemaVariableList';
|
||||
import VariableList from './formula/VariableList';
|
||||
@ -132,7 +132,7 @@ import InputTable from './InputTable';
|
||||
import type {InputTableColumnProps} from './InputTable';
|
||||
import ConfirmBox from './ConfirmBox';
|
||||
import DndContainer from './DndContainer';
|
||||
import Menu from './menu';
|
||||
import Menu from './Menu';
|
||||
import InputBoxWithSuggestion from './InputBoxWithSuggestion';
|
||||
import {CodeMirrorEditor} from './CodeMirror';
|
||||
import type CodeMirror from 'codemirror';
|
||||
|
@ -12,5 +12,11 @@ import './themes/default';
|
||||
import type {SchemaEditorItemPlaceholder} from './components/schema-editor/Common';
|
||||
import {schemaEditorItemPlaceholder} from './components/schema-editor/Common';
|
||||
import withStore from './withStore';
|
||||
import withRemoteConfig from './withRemoteConfig';
|
||||
|
||||
export {schemaEditorItemPlaceholder, SchemaEditorItemPlaceholder, withStore};
|
||||
export {
|
||||
schemaEditorItemPlaceholder,
|
||||
SchemaEditorItemPlaceholder,
|
||||
withStore,
|
||||
withRemoteConfig
|
||||
};
|
||||
|
2
packages/amis-ui/src/withRemoteConfig.ts
Normal file
2
packages/amis-ui/src/withRemoteConfig.ts
Normal file
@ -0,0 +1,2 @@
|
||||
import {withRemoteConfig} from './components/WithRemoteConfig';
|
||||
export default withRemoteConfig;
|
File diff suppressed because it is too large
Load Diff
@ -3,7 +3,7 @@ import * as renderer from 'react-test-renderer';
|
||||
import {fireEvent, render, waitFor} from '@testing-library/react';
|
||||
import '../../../src';
|
||||
import {render as amisRender} from '../../../src';
|
||||
import {makeEnv} from '../../helper';
|
||||
import {makeEnv, replaceReactAriaIds, wait} from '../../helper';
|
||||
|
||||
test('doAction:crud reload', async () => {
|
||||
const notify = jest.fn();
|
||||
@ -243,6 +243,8 @@ test('doAction:crud reload', async () => {
|
||||
);
|
||||
});
|
||||
|
||||
await wait(500);
|
||||
replaceReactAriaIds(container);
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
@ -407,6 +409,7 @@ test('doAction:crud reload with data1', async () => {
|
||||
);
|
||||
});
|
||||
|
||||
replaceReactAriaIds(container);
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
@ -574,5 +577,6 @@ test('doAction:crud reload with data2', async () => {
|
||||
);
|
||||
});
|
||||
|
||||
replaceReactAriaIds(container);
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
@ -112,6 +112,13 @@ export function replaceReactAriaIds(container: HTMLElement) {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
container.querySelectorAll('[data-id]').forEach(el => {
|
||||
const val = el.getAttribute('data-id');
|
||||
if (typeof val === 'string' && /^[a-z0-9]{12}$/.test(val)) {
|
||||
el.removeAttribute('data-id');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Mock IntersectionObserver
|
||||
|
@ -24,7 +24,6 @@ import {
|
||||
import '../../../src';
|
||||
import {render as amisRender, clearStoresCache} from '../../../src';
|
||||
import {makeEnv, replaceReactAriaIds, wait} from '../../helper';
|
||||
import {Select} from 'packages/amis-ui/lib/components/Select';
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
|
@ -226,7 +226,8 @@
|
||||
"\\.svg\\.js$": "<rootDir>/../../__mocks__/svgJsMock.js",
|
||||
"^amis\\-core$": "<rootDir>/../amis-core/src/index.tsx",
|
||||
"^amis\\-ui$": "<rootDir>/../amis-ui/src/index.tsx",
|
||||
"^amis\\-ui/lib/(.*)$": "<rootDir>/../amis-ui/src/$1"
|
||||
"^amis\\-ui/lib/(.*)$": "<rootDir>/../amis-ui/src/$1",
|
||||
"^amis\\-formula$": "<rootDir>/../amis-formula/src/index.ts"
|
||||
},
|
||||
"setupFilesAfterEnv": [
|
||||
"<rootDir>/../amis-core/__tests__/jest.setup.js"
|
||||
|
@ -227,7 +227,7 @@ function getPlugins(format = 'esm') {
|
||||
return `amis-ui/lib/components/Toast`;
|
||||
} else if ('NotFound' === name) {
|
||||
return `amis-ui/lib/components/404`;
|
||||
} else if ('withStore' === name) {
|
||||
} else if (['withStore', 'withRemoteConfig'].includes(name)) {
|
||||
return `amis-ui/lib/${name}`;
|
||||
} /* else if (name[0].toUpperCase() === name[0]) {
|
||||
return `amis-ui/lib/components/${name}`;
|
||||
|
@ -8,6 +8,7 @@
|
||||
export * from 'amis-core';
|
||||
export * from 'amis-ui';
|
||||
import './minimal';
|
||||
import {registerFilter, registerFormula} from 'amis-formula';
|
||||
|
||||
import type {
|
||||
BaseSchema,
|
||||
@ -44,5 +45,7 @@ export {
|
||||
SchemaExpression,
|
||||
Action,
|
||||
SchemaType,
|
||||
EditorAvailableLanguages
|
||||
EditorAvailableLanguages,
|
||||
registerFilter,
|
||||
registerFormula
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user