mirror of
https://gitee.com/baidu/amis.git
synced 2024-12-04 04:48:32 +08:00
Merge branch 'master' into style/dark-code
This commit is contained in:
commit
26f143c455
23
.swcrc
Normal file
23
.swcrc
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/swcrc",
|
||||
"jsc": {
|
||||
"parser": {
|
||||
"syntax": "typescript",
|
||||
"tsx": true,
|
||||
"decorators": true,
|
||||
"dynamicImport": true
|
||||
},
|
||||
"transform": {
|
||||
"decoratorMetadata": true,
|
||||
"legacyDecorator": true,
|
||||
"react": {
|
||||
"runtime": "classic"
|
||||
}
|
||||
},
|
||||
"keepClassNames": true,
|
||||
"externalHelpers": true,
|
||||
"loose": false
|
||||
},
|
||||
"sourceMaps": true,
|
||||
"minify": false
|
||||
}
|
14
README.md
14
README.md
@ -7,7 +7,7 @@
|
||||
[文档(国外)](https://baidu.github.io/amis/) |
|
||||
[可视化编辑器](https://aisuda.github.io/amis-editor-demo/) |
|
||||
[amis-admin](https://github.com/aisuda/amis-admin) |
|
||||
[爱速搭](https://aisuda.bce.baidu.com/aisuda-docs/)
|
||||
[爱速搭](https://aisuda.baidu.com/)
|
||||
|
||||
</div>
|
||||
|
||||
@ -63,7 +63,13 @@ npm test --workspaces
|
||||
|
||||
# 测试某个用例
|
||||
# <spec-name>为用例名称,比如inputImage
|
||||
npm test --workspace amis <spec-name>
|
||||
npm test --workspace amis -- -t <spec-name>
|
||||
|
||||
# 运行某个单测文件
|
||||
./node_modules/.bin/jest packages/amis/__tests__/renderers/Form/buttonToolBar.test.tsx
|
||||
|
||||
# 运行某个单测文件里的某个例子
|
||||
./node_modules/.bin/jest packages/amis/__tests__/renderers/Form/buttonToolBar.test.tsx -t 'Renderer:button-toolbar'
|
||||
|
||||
# 查看测试用例覆盖率
|
||||
npm run coverage
|
||||
@ -73,7 +79,7 @@ npm run update-snapshot
|
||||
|
||||
# 更新单个 snapshot
|
||||
# <spec-name>为用例名称,比如inputImage
|
||||
npm run update-snapshot --workspace amis <spec-name>
|
||||
npm run update-snapshot --workspace amis -- -t <spec-name>
|
||||
```
|
||||
|
||||
### 发布版本
|
||||
@ -106,4 +112,4 @@ npm run release
|
||||
|
||||
## 低代码平台
|
||||
|
||||
amis 只能实现前端低代码,如果需要完整的低代码平台推荐使用[爱速搭](https://aisuda.bce.baidu.com/aisuda-docs/)。
|
||||
amis 只能实现前端低代码,如果需要完整的低代码平台推荐使用[爱速搭](https://aisuda.baidu.com/)。
|
||||
|
@ -1444,6 +1444,75 @@ run action ajax
|
||||
| copyFormat | `string` | `text/html` | 复制格式 |
|
||||
| content | [模板](../../docs/concepts/template) | - | 指定复制的内容。可用 `${xxx}` 取值 |
|
||||
|
||||
### 打印
|
||||
|
||||
> 6.2.0 及以后版本
|
||||
|
||||
打印页面中的某个组件,对应的组件需要配置 `testid`,如果要打印多个,可以使用 `"testids": ["x", "y"]` 来打印多个组件
|
||||
|
||||
```schema
|
||||
{
|
||||
type: 'page',
|
||||
body: [
|
||||
{
|
||||
type: 'button',
|
||||
label: '打印',
|
||||
level: 'primary',
|
||||
className: 'mr-2',
|
||||
onEvent: {
|
||||
click: {
|
||||
actions: [
|
||||
{
|
||||
actionType: 'print',
|
||||
args: {
|
||||
testid: 'mycrud'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "crud",
|
||||
"api": "/api/mock2/sample",
|
||||
"testid": "mycrud",
|
||||
"syncLocation": false,
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"label": "ID"
|
||||
},
|
||||
{
|
||||
"name": "engine",
|
||||
"label": "Rendering engine"
|
||||
},
|
||||
{
|
||||
"name": "browser",
|
||||
"label": "Browser"
|
||||
},
|
||||
{
|
||||
"name": "platform",
|
||||
"label": "Platform(s)"
|
||||
},
|
||||
{
|
||||
"name": "version",
|
||||
"label": "Engine version"
|
||||
},
|
||||
{
|
||||
"name": "grade",
|
||||
"label": "CSS grade"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
| 属性名 | 类型 | 默认值 | 说明 |
|
||||
| ------- | ---------- | ------ | ----------------- |
|
||||
| testid | `string` | | 组件的 testid |
|
||||
| testids | `string[]` | - | 多个组件的 testid |
|
||||
|
||||
### 发送邮件
|
||||
|
||||
通过配置`actionType: 'email'`和邮件属性实现发送邮件操作。
|
||||
|
@ -303,7 +303,16 @@ export default {
|
||||
body: {
|
||||
type: 'form',
|
||||
name: 'sample-edit-form',
|
||||
api: '/api/sample/$id',
|
||||
data:{
|
||||
env: 'test'
|
||||
},
|
||||
api: {
|
||||
method:'post',
|
||||
url:'/api/sample/$id',
|
||||
messages:{
|
||||
success: '成功了-${env}'
|
||||
}
|
||||
},
|
||||
body: [
|
||||
{
|
||||
type: 'input-text',
|
||||
|
@ -52,6 +52,9 @@
|
||||
"@babel/types": "^7.22.5",
|
||||
"@fortawesome/fontawesome-free": "^6.1.1",
|
||||
"@rollup/plugin-replace": "^5.0.1",
|
||||
"@swc/core": "^1.3.107",
|
||||
"@swc/helpers": "^0.5.3",
|
||||
"@swc/jest": "^0.2.34",
|
||||
"@types/express": "^4.17.14",
|
||||
"@types/jest": "^28.1.0",
|
||||
"@types/js-yaml": "^4.0.5",
|
||||
@ -117,7 +120,9 @@
|
||||
"tsx",
|
||||
"js"
|
||||
],
|
||||
"preset": "ts-jest",
|
||||
"transform": {
|
||||
"^.+\\.(t|j)sx?$": "@swc/jest"
|
||||
},
|
||||
"setupFiles": [
|
||||
"jest-canvas-mock"
|
||||
],
|
||||
@ -144,4 +149,4 @@
|
||||
"printBasicPrototype": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
22
packages/amis-core/.swcrc
Normal file
22
packages/amis-core/.swcrc
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/swcrc",
|
||||
"jsc": {
|
||||
"parser": {
|
||||
"syntax": "typescript",
|
||||
"tsx": true,
|
||||
"decorators": true,
|
||||
"dynamicImport": true
|
||||
},
|
||||
"transform": {
|
||||
"decoratorMetadata": true,
|
||||
"legacyDecorator": true,
|
||||
"react": {
|
||||
"runtime": "classic"
|
||||
}
|
||||
},
|
||||
"keepClassNames": true,
|
||||
"externalHelpers": true,
|
||||
"loose": false
|
||||
},
|
||||
"minify": false
|
||||
}
|
@ -11,6 +11,7 @@ import {makeEnv} from './helper';
|
||||
test('Scoped splitTarget', async () => {
|
||||
expect(splitTarget('abc')).toEqual(['abc']);
|
||||
expect(splitTarget('a,b,c')).toEqual(['a', 'b', 'c']);
|
||||
expect(splitTarget('a, b, c ')).toEqual(['a', 'b', 'c']);
|
||||
expect(splitTarget('a?x=1&y=2,b,c')).toEqual(['a?x=1&y=2', 'b', 'c']);
|
||||
expect(splitTarget('a?x=${[a, b]},b,c')).toEqual(['a?x=${[a, b]}', 'b', 'c']);
|
||||
expect(splitTarget('a?x=${[a, b]}')).toEqual(['a?x=${[a, b]}']);
|
||||
|
@ -85,12 +85,7 @@
|
||||
"js"
|
||||
],
|
||||
"transform": {
|
||||
"\\.(ts|tsx)$": [
|
||||
"ts-jest",
|
||||
{
|
||||
"diagnostics": false
|
||||
}
|
||||
]
|
||||
"^.+\\.(t|j)sx?$": "@swc/jest"
|
||||
},
|
||||
"setupFiles": [
|
||||
"jest-canvas-mock"
|
||||
@ -109,4 +104,4 @@
|
||||
]
|
||||
},
|
||||
"gitHead": "37d23b4a8eb1c663bc38e8dd9040889ea1526ec4"
|
||||
}
|
||||
}
|
@ -68,7 +68,7 @@ export function splitTarget(target: string): Array<string> {
|
||||
let parts: Array<string> = [];
|
||||
|
||||
pos.reduceRight((arr: Array<string>, index) => {
|
||||
arr.unshift(target.slice(index + 1));
|
||||
arr.unshift(target.slice(index + 1)?.trim());
|
||||
target = target.slice(0, index);
|
||||
return arr;
|
||||
}, parts);
|
||||
|
@ -267,7 +267,7 @@ export function HocStoreFactory(renderer: {
|
||||
props.store?.storeType === 'ComboStore'
|
||||
? undefined
|
||||
: syncDataFromSuper(
|
||||
store.data,
|
||||
{...store.data, ...props.data},
|
||||
(props.data as any).__super,
|
||||
(prevProps.data as any).__super,
|
||||
store,
|
||||
|
51
packages/amis-core/src/actions/PrintAction.ts
Normal file
51
packages/amis-core/src/actions/PrintAction.ts
Normal file
@ -0,0 +1,51 @@
|
||||
import {printElements} from '../utils/printElement';
|
||||
import {RendererEvent} from '../utils/renderer-event';
|
||||
import {
|
||||
RendererAction,
|
||||
ListenerAction,
|
||||
ListenerContext,
|
||||
registerAction
|
||||
} from './Action';
|
||||
|
||||
export interface IPrintAction extends ListenerAction {
|
||||
actionType: 'copy';
|
||||
args: {
|
||||
testid?: string;
|
||||
testids?: string[];
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印动作
|
||||
*
|
||||
* @export
|
||||
* @class PrintAction
|
||||
* @implements {Action}
|
||||
*/
|
||||
export class PrintAction implements RendererAction {
|
||||
async run(
|
||||
action: IPrintAction,
|
||||
renderer: ListenerContext,
|
||||
event: RendererEvent<any>
|
||||
) {
|
||||
if (action.args?.testid) {
|
||||
const element = document.querySelector(
|
||||
`[data-testid='${action.args.testid}']`
|
||||
);
|
||||
if (element) {
|
||||
printElements([element]);
|
||||
}
|
||||
} else if (action.args?.testids) {
|
||||
const elements: Element[] = [];
|
||||
action.args.testids.forEach(testid => {
|
||||
const element = document.querySelector(`[data-testid='${testid}']`);
|
||||
if (element) {
|
||||
elements.push(element);
|
||||
}
|
||||
});
|
||||
printElements(elements);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
registerAction('print', new PrintAction());
|
@ -19,5 +19,6 @@ import './EmailAction';
|
||||
import './LinkAction';
|
||||
import './ToastAction';
|
||||
import './PageAction';
|
||||
import './PrintAction';
|
||||
|
||||
export * from './Action';
|
||||
|
@ -206,7 +206,8 @@ export {
|
||||
splitTarget,
|
||||
CustomStyle,
|
||||
enableDebug,
|
||||
disableDebug
|
||||
disableDebug,
|
||||
envOverwrite
|
||||
};
|
||||
|
||||
export function render(
|
||||
|
@ -49,7 +49,7 @@ import LazyComponent from '../components/LazyComponent';
|
||||
import {isAlive} from 'mobx-state-tree';
|
||||
|
||||
import type {LabelAlign} from './Item';
|
||||
import {injectObjectChain} from '../utils';
|
||||
import {buildTestId, injectObjectChain} from '../utils';
|
||||
import {reaction} from 'mobx';
|
||||
|
||||
export interface FormHorizontal {
|
||||
@ -1808,7 +1808,8 @@ export default class Form extends React.Component<FormProps, object> {
|
||||
render,
|
||||
staticClassName,
|
||||
static: isStatic = false,
|
||||
loadingConfig
|
||||
loadingConfig,
|
||||
testid
|
||||
} = this.props;
|
||||
|
||||
const {restError} = store;
|
||||
@ -1840,6 +1841,7 @@ export default class Form extends React.Component<FormProps, object> {
|
||||
)}
|
||||
onSubmit={this.handleFormSubmit}
|
||||
noValidate
|
||||
{...buildTestId(testid)}
|
||||
>
|
||||
{/* 实现回车自动提交 */}
|
||||
<input type="submit" style={{display: 'none'}} />
|
||||
|
@ -468,7 +468,7 @@ export function wrapControl<
|
||||
|
||||
setInitialValue(value: any) {
|
||||
const model = this.model!;
|
||||
const {formStore: form, data} = this.props;
|
||||
const {formStore: form, data, canAccessSuperData} = this.props;
|
||||
const isExp = isExpression(value);
|
||||
|
||||
if (isExp) {
|
||||
@ -479,10 +479,22 @@ export function wrapControl<
|
||||
} else {
|
||||
let initialValue = model.extraName
|
||||
? [
|
||||
getVariable(data, model.name, form?.canAccessSuperData),
|
||||
getVariable(data, model.extraName, form?.canAccessSuperData)
|
||||
getVariable(
|
||||
data,
|
||||
model.name,
|
||||
canAccessSuperData ?? form?.canAccessSuperData
|
||||
),
|
||||
getVariable(
|
||||
data,
|
||||
model.extraName,
|
||||
canAccessSuperData ?? form?.canAccessSuperData
|
||||
)
|
||||
]
|
||||
: getVariable(data, model.name, form?.canAccessSuperData);
|
||||
: getVariable(
|
||||
data,
|
||||
model.name,
|
||||
canAccessSuperData ?? form?.canAccessSuperData
|
||||
);
|
||||
|
||||
if (
|
||||
model.extraName &&
|
||||
|
@ -6,7 +6,8 @@ import {ServerError} from '../utils/errors';
|
||||
import {normalizeApiResponseData} from '../utils/api';
|
||||
import {replaceText} from '../utils/replaceText';
|
||||
import {concatData} from '../utils/concatData';
|
||||
|
||||
import {envOverwrite} from '../envOverwrite';
|
||||
import {filter} from 'amis-core';
|
||||
export const ServiceStore = iRendererStore
|
||||
.named('ServiceStore')
|
||||
.props({
|
||||
@ -54,7 +55,7 @@ export const ServiceStore = iRendererStore
|
||||
}
|
||||
|
||||
function updateMessage(msg?: string, error: boolean = false) {
|
||||
self.msg = (msg && String(msg)) || '';
|
||||
self.msg = (msg && filter(msg, self.data)) || '';
|
||||
self.error = error;
|
||||
}
|
||||
|
||||
@ -445,6 +446,7 @@ export const ServiceStore = iRendererStore
|
||||
} else {
|
||||
if (json.data) {
|
||||
const env = getEnv(self);
|
||||
json.data = envOverwrite(json.data, env.locale);
|
||||
json.data = replaceText(
|
||||
json.data,
|
||||
env.replaceText,
|
||||
|
@ -487,6 +487,7 @@ export const TableStore = iRendererStore
|
||||
.named('TableStore')
|
||||
.props({
|
||||
columns: types.array(Column),
|
||||
columnsKey: '',
|
||||
rows: types.array(Row),
|
||||
selectedRows: types.array(types.reference(Row)),
|
||||
expandedRows: types.array(types.string),
|
||||
@ -1105,6 +1106,7 @@ export const TableStore = iRendererStore
|
||||
(self.tableLayout = config.tableLayout);
|
||||
|
||||
if (config.columns && Array.isArray(config.columns)) {
|
||||
self.columnsKey = getPersistDataKey(config.columns);
|
||||
let columns: Array<SColumn> = config.columns
|
||||
.map(column => {
|
||||
if (
|
||||
@ -1123,7 +1125,7 @@ export const TableStore = iRendererStore
|
||||
.filter(column => column);
|
||||
|
||||
// 更新列顺序,afterCreate生命周期中更新columns不会触发组件的render
|
||||
const key = getPersistDataKey(columns);
|
||||
const key = self.columnsKey;
|
||||
const data = localStorage.getItem(key);
|
||||
let tableMetaData = null;
|
||||
|
||||
@ -1286,7 +1288,7 @@ export const TableStore = iRendererStore
|
||||
typeof column.pristine.width === 'number'
|
||||
? `width: ${column.pristine.width}px;`
|
||||
: column.pristine.width
|
||||
? `width: ${column.pristine.width};`
|
||||
? `width: ${column.pristine.width};min-width: ${column.pristine.width};`
|
||||
: '' // todo 可能需要让修改过列宽的保持相应宽度,目前这样相当于重置了
|
||||
}`;
|
||||
});
|
||||
@ -1841,7 +1843,7 @@ export const TableStore = iRendererStore
|
||||
* 前端持久化记录列排序,查询字段,显示列信息
|
||||
*/
|
||||
function persistSaveToggledColumns() {
|
||||
const key = getPersistDataKey(self.columnsData);
|
||||
const key = self.columnsKey;
|
||||
|
||||
localStorage.setItem(
|
||||
key,
|
||||
@ -1947,7 +1949,7 @@ export const TableStore = iRendererStore
|
||||
if (!isAlive(self)) {
|
||||
return;
|
||||
}
|
||||
const key = getPersistDataKey(self.columnsData);
|
||||
const key = self.columnsKey;
|
||||
const data = localStorage.getItem(key);
|
||||
|
||||
if (data) {
|
||||
|
@ -368,7 +368,7 @@ export function responseAdaptor(ret: fetcherResult, api: ApiObject) {
|
||||
|
||||
// 返回内容是 string,说明 content-type 不是 json,这时可能是返回了纯文本或 html
|
||||
if (typeof data === 'string') {
|
||||
const contentType = (ret.headers as any)['content-type'] || '';
|
||||
const contentType = (ret.headers as any)?.['content-type'] || '';
|
||||
// 如果是文本类型就尝试解析一下
|
||||
if (
|
||||
ret.headers &&
|
||||
|
@ -38,7 +38,7 @@ export function attachmentAdpator(
|
||||
}
|
||||
}
|
||||
|
||||
let type = response.headers['content-type'];
|
||||
let type = response.headers?.['content-type'];
|
||||
let blob =
|
||||
response.data.toString() === '[object Blob]'
|
||||
? response.data
|
||||
|
@ -2,3 +2,10 @@ export const chromeVersion = (function getChromeVersion() {
|
||||
const raw = navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./);
|
||||
return raw ? parseInt(raw[2], 10) : false;
|
||||
})();
|
||||
|
||||
export const isSafari =
|
||||
navigator.vendor &&
|
||||
navigator.vendor.indexOf('Apple') > -1 &&
|
||||
navigator.userAgent &&
|
||||
navigator.userAgent.indexOf('CriOS') == -1 &&
|
||||
navigator.userAgent.indexOf('FxiOS') == -1;
|
||||
|
@ -169,7 +169,7 @@ export function calculatePosition(
|
||||
: overlayHeight / 2;
|
||||
|
||||
// 如果还有其他可选项,则做位置判断,是否在可视区域,不完全在则继续看其他定位情况。
|
||||
if (tests.length) {
|
||||
if (tests.length || isAuto) {
|
||||
const transformed = {
|
||||
x: clip.x + positionLeft / scaleX,
|
||||
y: clip.y + positionTop / scaleY,
|
||||
@ -200,6 +200,10 @@ export function calculatePosition(
|
||||
|
||||
if (visibleX && visibleY) {
|
||||
break;
|
||||
} else if (isAuto && tests.length === 0) {
|
||||
// 如果是 auto 模式,且最后一个方向都不可见,则直接平移到可见区域
|
||||
visibleY || (positionTop = window.innerHeight - transformed.height);
|
||||
visibleX || (positionLeft = window.innerWidth - transformed.width);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
76
packages/amis-core/src/utils/printElement.ts
Normal file
76
packages/amis-core/src/utils/printElement.ts
Normal file
@ -0,0 +1,76 @@
|
||||
/**
|
||||
* 打印元素,参考 https://github.com/szepeshazi/print-elements 里的实现
|
||||
* 原理就是遍历节点加上打印样式,然后打印完了再清理掉
|
||||
* 对代码做了改造和优化
|
||||
*/
|
||||
|
||||
const hideFromPrintClass = 'pe-no-print';
|
||||
const preservePrintClass = 'pe-preserve-print';
|
||||
const preserveAncestorClass = 'pe-preserve-ancestor';
|
||||
const bodyElementName = 'BODY';
|
||||
|
||||
function hide(element: Element) {
|
||||
if (!element.classList.contains(preservePrintClass)) {
|
||||
element.classList.add(hideFromPrintClass);
|
||||
}
|
||||
}
|
||||
|
||||
function preserve(element: Element, isStartingElement: boolean) {
|
||||
element.classList.remove(hideFromPrintClass);
|
||||
element.classList.add(preservePrintClass);
|
||||
if (!isStartingElement) {
|
||||
element.classList.add(preserveAncestorClass);
|
||||
}
|
||||
}
|
||||
|
||||
function clean(element: Element) {
|
||||
element.classList.remove(hideFromPrintClass);
|
||||
element.classList.remove(preservePrintClass);
|
||||
element.classList.remove(preserveAncestorClass);
|
||||
}
|
||||
|
||||
function walkSiblings(element: Element, callback: (element: Element) => void) {
|
||||
let sibling = element.previousElementSibling;
|
||||
while (sibling) {
|
||||
callback(sibling);
|
||||
sibling = sibling.previousElementSibling;
|
||||
}
|
||||
sibling = element.nextElementSibling;
|
||||
while (sibling) {
|
||||
callback(sibling);
|
||||
sibling = sibling.nextElementSibling;
|
||||
}
|
||||
}
|
||||
|
||||
function attachPrintClasses(element: Element, isStartingElement: boolean) {
|
||||
preserve(element, isStartingElement);
|
||||
walkSiblings(element, hide);
|
||||
}
|
||||
|
||||
function cleanup(element: Element, isStartingElement: boolean) {
|
||||
clean(element);
|
||||
walkSiblings(element, clean);
|
||||
}
|
||||
|
||||
function walkTree(
|
||||
element: Element,
|
||||
callback: (element: Element, isStartingElement: boolean) => void
|
||||
) {
|
||||
let currentElement: Element | null = element;
|
||||
callback(currentElement, true);
|
||||
currentElement = currentElement.parentElement;
|
||||
while (currentElement && currentElement.nodeName !== bodyElementName) {
|
||||
callback(currentElement, false);
|
||||
currentElement = currentElement.parentElement;
|
||||
}
|
||||
}
|
||||
|
||||
export function printElements(elements: Element[]) {
|
||||
for (let i = 0; i < elements.length; i++) {
|
||||
walkTree(elements[i], attachPrintClasses);
|
||||
}
|
||||
window.print();
|
||||
for (let i = 0; i < elements.length; i++) {
|
||||
walkTree(elements[i], cleanup);
|
||||
}
|
||||
}
|
@ -53,6 +53,7 @@ export default class MiniEditor extends Editor {
|
||||
theme={theme}
|
||||
data={data}
|
||||
autoFocus={autoFocus}
|
||||
appLocale={this.props.appLocale}
|
||||
></Preview>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -812,14 +812,19 @@ export class CRUDPlugin extends BasePlugin {
|
||||
api: valueSchema.api?.method?.match(/^(post|put)$/i)
|
||||
? valueSchema.api
|
||||
: {...valueSchema.api, method: 'post'},
|
||||
body: valueSchema.columns.map((column: ColumnItem) => {
|
||||
const type = column.type;
|
||||
return {
|
||||
type: viewTypeToEditType(type),
|
||||
name: column.name,
|
||||
label: column.label
|
||||
};
|
||||
})
|
||||
body: valueSchema.columns
|
||||
.filter(
|
||||
({type}: any) =>
|
||||
type !== 'progress' && type !== 'operation'
|
||||
)
|
||||
.map((column: ColumnItem) => {
|
||||
const type = column.type;
|
||||
return {
|
||||
type: viewTypeToEditType(type),
|
||||
name: column.name,
|
||||
label: column.label
|
||||
};
|
||||
})
|
||||
};
|
||||
valueSchema.headerToolbar = [createSchemaBase, 'bulkActions'];
|
||||
}
|
||||
|
@ -233,13 +233,15 @@ export class TableViewPlugin extends BasePlugin {
|
||||
name: 'border',
|
||||
type: 'switch',
|
||||
mode: 'row',
|
||||
pipeIn: defaultValue(true),
|
||||
inputClassName: 'inline-flex justify-between flex-row-reverse'
|
||||
},
|
||||
{
|
||||
label: '边框颜色',
|
||||
type: 'input-color',
|
||||
name: 'borderColor',
|
||||
visibleOn: 'this.border',
|
||||
visibleOn:
|
||||
'this.border || typeof this.border === "undefined"',
|
||||
pipeIn: defaultValue('#eceff8')
|
||||
}
|
||||
]
|
||||
|
@ -324,7 +324,7 @@ export default class TransferTableOption extends React.Component<
|
||||
return {
|
||||
type: 'action',
|
||||
actionType: 'dialog',
|
||||
label: '添加表格列',
|
||||
label: '设置表格列',
|
||||
level: 'enhance',
|
||||
dialog: {
|
||||
title: '设置表格列选项',
|
||||
@ -348,12 +348,14 @@ export default class TransferTableOption extends React.Component<
|
||||
{
|
||||
type: 'input-text',
|
||||
name: 'label',
|
||||
placeholder: '标题'
|
||||
placeholder: '标题',
|
||||
required: true
|
||||
},
|
||||
{
|
||||
type: 'input-text',
|
||||
name: 'name',
|
||||
placeholder: '绑定字段名'
|
||||
placeholder: '绑定字段名',
|
||||
required: true
|
||||
},
|
||||
{
|
||||
type: 'select',
|
||||
@ -417,7 +419,7 @@ export default class TransferTableOption extends React.Component<
|
||||
{
|
||||
type: 'action',
|
||||
actionType: 'dialog',
|
||||
label: '添加表格行',
|
||||
label: '设置表格行',
|
||||
level: 'enhance',
|
||||
disabled: columns && columns.length === 0,
|
||||
block: true,
|
||||
|
@ -95,12 +95,7 @@
|
||||
"js"
|
||||
],
|
||||
"transform": {
|
||||
"\\.(ts|tsx)$": [
|
||||
"ts-jest",
|
||||
{
|
||||
"diagnostics": false
|
||||
}
|
||||
]
|
||||
"^.+\\.(t|j)sx?$": "@swc/jest"
|
||||
},
|
||||
"setupFiles": [
|
||||
"jest-canvas-mock"
|
||||
@ -119,4 +114,4 @@
|
||||
}
|
||||
},
|
||||
"gitHead": "37d23b4a8eb1c663bc38e8dd9040889ea1526ec4"
|
||||
}
|
||||
}
|
@ -6,7 +6,7 @@
|
||||
"module": "esm/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\"",
|
||||
"test": "echo \"Warnings: no test specified\"",
|
||||
"build": "npm run clean-dist && NODE_ENV=production rollup -c ",
|
||||
"clean-dist": "rimraf lib/** esm/**",
|
||||
"i18n:update": "npx i18n update --config=./i18nConfig.js",
|
||||
|
@ -282,7 +282,7 @@ export class ParseThemeData {
|
||||
|
||||
// 解析组件通用方法
|
||||
parseComponentCommon(component: any) {
|
||||
if (component.token) {
|
||||
if (component.token && component.body) {
|
||||
// 有token时结束递归
|
||||
const token = component.token;
|
||||
for (let key in component.body) {
|
||||
|
@ -123,12 +123,7 @@
|
||||
"js"
|
||||
],
|
||||
"transform": {
|
||||
"\\.(ts|tsx)$": [
|
||||
"ts-jest",
|
||||
{
|
||||
"diagnostics": false
|
||||
}
|
||||
]
|
||||
"^.+\\.(t|j)sx?$": "@swc/jest"
|
||||
},
|
||||
"setupFiles": [
|
||||
"jest-canvas-mock"
|
||||
@ -148,4 +143,4 @@
|
||||
]
|
||||
},
|
||||
"gitHead": "37d23b4a8eb1c663bc38e8dd9040889ea1526ec4"
|
||||
}
|
||||
}
|
@ -2,11 +2,16 @@
|
||||
height: px2rem(30px);
|
||||
line-height: px2rem(30px);
|
||||
font-size: px2rem(12px);
|
||||
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0 0 0 var(--gap-md);
|
||||
border-bottom: var(--borderWidth) solid var(--borderColor);
|
||||
|
||||
a {
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
&-item {
|
||||
display: inline-block;
|
||||
}
|
||||
|
13
packages/amis-ui/scss/components/_print.scss
Normal file
13
packages/amis-ui/scss/components/_print.scss
Normal file
@ -0,0 +1,13 @@
|
||||
@media print {
|
||||
.pe-no-print {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.pe-preserve-ancestor {
|
||||
display: block !important;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
border: none !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
}
|
@ -142,3 +142,5 @@
|
||||
@import '../components/debug';
|
||||
@import '../components/menu';
|
||||
@import '../components/overflow-tpl';
|
||||
|
||||
@import '../components/print';
|
||||
|
@ -54,6 +54,10 @@ export interface TabsTransferProps
|
||||
ctx?: Record<string, any>;
|
||||
selectMode?: 'table' | 'list' | 'tree' | 'chained' | 'associated';
|
||||
searchable?: boolean;
|
||||
/**
|
||||
* 是否默认都展开
|
||||
*/
|
||||
initiallyOpen?: boolean;
|
||||
}
|
||||
|
||||
export interface TabsTransferState {
|
||||
@ -127,7 +131,6 @@ export class TabsTransfer extends React.Component<
|
||||
if (!Array.isArray(result)) {
|
||||
throw new Error('onSearch 需要返回数组');
|
||||
}
|
||||
|
||||
this.setState({
|
||||
searchResult: result
|
||||
});
|
||||
@ -171,12 +174,15 @@ export class TabsTransfer extends React.Component<
|
||||
onlyChildren,
|
||||
selectMode,
|
||||
loadingConfig,
|
||||
activeKey,
|
||||
options: optionsConfig,
|
||||
valueField = 'value',
|
||||
labelField = 'label'
|
||||
} = this.props;
|
||||
const options = searchResult || [];
|
||||
const mode = searchResultMode || selectMode; // 没有配置时默认和左侧选项展示形式一致
|
||||
|
||||
const activeTab = optionsConfig[activeKey];
|
||||
return mode === 'table' ? (
|
||||
<TableCheckboxes
|
||||
placeholder={noResultsText}
|
||||
@ -204,6 +210,7 @@ export class TabsTransfer extends React.Component<
|
||||
showIcon={false}
|
||||
multiple={true}
|
||||
cascade={true}
|
||||
autoCheckChildren={activeTab.autoCheckChildren}
|
||||
itemRender={
|
||||
optionItemRender
|
||||
? (item: Option, states: ItemRenderStates) =>
|
||||
@ -349,6 +356,7 @@ export class TabsTransfer extends React.Component<
|
||||
virtualThreshold,
|
||||
onlyChildren,
|
||||
loadingConfig,
|
||||
initiallyOpen = true,
|
||||
valueField = 'value',
|
||||
labelField = 'label',
|
||||
deferField = 'defer'
|
||||
@ -400,6 +408,7 @@ export class TabsTransfer extends React.Component<
|
||||
virtualThreshold={virtualThreshold}
|
||||
valueField={valueField}
|
||||
labelField={labelField}
|
||||
initiallyOpen={initiallyOpen}
|
||||
/>
|
||||
) : selectMode === 'chained' ? (
|
||||
<ChainedCheckboxes
|
||||
|
@ -51,6 +51,7 @@ export class TransferPicker extends React.Component<TabsTransferPickerProps> {
|
||||
popOverContainer,
|
||||
maxTagCount,
|
||||
overflowTagPopover,
|
||||
placeholder,
|
||||
...rest
|
||||
} = this.props;
|
||||
|
||||
@ -100,7 +101,7 @@ export class TransferPicker extends React.Component<TabsTransferPickerProps> {
|
||||
result={value}
|
||||
onResultChange={onChange}
|
||||
onResultClick={onClick}
|
||||
placeholder={__('Select.placeholder')}
|
||||
placeholder={placeholder ?? __('Select.placeholder')}
|
||||
disabled={disabled}
|
||||
itemRender={option => (
|
||||
<span>{(option && option[labelField]) || 'undefiend'}</span>
|
||||
|
@ -79,8 +79,14 @@ export interface TransferProps
|
||||
onChange?: (value: Array<Option>, optionModified?: boolean) => void;
|
||||
onSearch?: (
|
||||
term: string,
|
||||
setCancel: (cancel: () => void) => void
|
||||
) => Promise<Options | void>;
|
||||
setCancel: (cancel: () => void) => void,
|
||||
targetPage?: {page: number; perPage?: number}
|
||||
) => Promise<{
|
||||
items: Options;
|
||||
page?: number;
|
||||
perPage?: number;
|
||||
total?: number;
|
||||
} | void>;
|
||||
|
||||
// 自定义选择框相关
|
||||
selectRender?: (
|
||||
@ -151,12 +157,21 @@ export interface TransferProps
|
||||
perPage?: number,
|
||||
direction?: 'forward' | 'backward'
|
||||
) => void;
|
||||
/**
|
||||
* 是否默认都展开
|
||||
*/
|
||||
initiallyOpen?: boolean;
|
||||
/**
|
||||
* ui级联关系,true代表级联选中,false代表不级联,默认为true
|
||||
*/
|
||||
autoCheckChildren?: boolean;
|
||||
}
|
||||
|
||||
export interface TransferState {
|
||||
tempValue?: Array<Option> | Option;
|
||||
inputValue: string;
|
||||
searchResult: Options | null;
|
||||
searchResultPage?: {page?: number; perPage?: number; total?: number} | null;
|
||||
isTreeDeferLoad: boolean;
|
||||
resultSelectMode: 'list' | 'tree' | 'table';
|
||||
}
|
||||
@ -188,6 +203,7 @@ export class Transfer<
|
||||
state: TransferState = {
|
||||
inputValue: '',
|
||||
searchResult: null,
|
||||
searchResultPage: null,
|
||||
isTreeDeferLoad: false,
|
||||
resultSelectMode: 'list'
|
||||
};
|
||||
@ -376,37 +392,50 @@ export class Transfer<
|
||||
handleSeachCancel() {
|
||||
this.setState({
|
||||
inputValue: '',
|
||||
searchResult: null
|
||||
searchResult: null,
|
||||
searchResultPage: null
|
||||
});
|
||||
}
|
||||
|
||||
lazySearch = debounce(
|
||||
async () => {
|
||||
const {inputValue} = this.state;
|
||||
if (!inputValue) {
|
||||
return;
|
||||
}
|
||||
const onSearch = this.props.onSearch!;
|
||||
let result = await onSearch(
|
||||
inputValue,
|
||||
(cancelExecutor: () => void) => (this.cancelSearch = cancelExecutor)
|
||||
);
|
||||
lazySearch = debounce(this.searchRequest, 250, {
|
||||
trailing: true,
|
||||
leading: false
|
||||
});
|
||||
|
||||
if (this.unmounted) {
|
||||
return;
|
||||
}
|
||||
@autobind
|
||||
async searchRequest(page?: number, perPage?: number) {
|
||||
const {pagination} = this.props;
|
||||
const {inputValue} = this.state;
|
||||
if (!inputValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Array.isArray(result)) {
|
||||
const onSearch = this.props.onSearch!;
|
||||
let result = await onSearch(
|
||||
inputValue,
|
||||
(cancelExecutor: () => void) => (this.cancelSearch = cancelExecutor),
|
||||
this.props.pagination?.enable
|
||||
? {page: page || 1, perPage: perPage || pagination?.perPage || 10}
|
||||
: undefined
|
||||
);
|
||||
|
||||
if (this.unmounted) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (result) {
|
||||
const {items, ...currentPage} = result;
|
||||
|
||||
if (!Array.isArray(items)) {
|
||||
throw new Error('onSearch 需要返回数组');
|
||||
}
|
||||
|
||||
this.setState({
|
||||
searchResult: result
|
||||
searchResult: items,
|
||||
searchResultPage: {...currentPage}
|
||||
});
|
||||
},
|
||||
250,
|
||||
{trailing: true, leading: false}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
getFlattenArr(options: Array<Option>) {
|
||||
const {valueField = 'value'} = this.props;
|
||||
@ -478,6 +507,22 @@ export class Transfer<
|
||||
});
|
||||
}
|
||||
|
||||
@autobind
|
||||
onPageChangeHandle(
|
||||
page: number,
|
||||
perPage?: number,
|
||||
direction?: 'forward' | 'backward'
|
||||
) {
|
||||
const {onPageChange, onSearch} = this.props;
|
||||
const {searchResult, inputValue} = this.state;
|
||||
|
||||
if (searchResult) {
|
||||
this.searchRequest(page, perPage);
|
||||
} else if (onPageChange) {
|
||||
onPageChange(page, perPage, direction);
|
||||
}
|
||||
}
|
||||
|
||||
renderSelect(
|
||||
props: TransferProps & {
|
||||
onToggleAll?: () => void;
|
||||
@ -597,24 +642,42 @@ export class Transfer<
|
||||
}
|
||||
|
||||
renderFooter() {
|
||||
const {classnames: cx, pagination, onPageChange} = this.props;
|
||||
const {classnames: cx, pagination} = this.props;
|
||||
const {searchResult, searchResultPage} = this.state;
|
||||
|
||||
return pagination?.enable ? (
|
||||
if (!pagination || !pagination?.enable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const currentPage =
|
||||
searchResult && searchResultPage
|
||||
? {
|
||||
page: searchResultPage.page,
|
||||
perPage: searchResultPage.perPage,
|
||||
total: searchResultPage.total
|
||||
}
|
||||
: {
|
||||
page: pagination.page,
|
||||
perPage: pagination.perPage,
|
||||
total: pagination.total
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={cx('Transfer-footer')}>
|
||||
<Pagination
|
||||
className={cx('Transfer-footer-pagination', pagination.className)}
|
||||
activePage={pagination.page}
|
||||
perPage={pagination.perPage}
|
||||
total={pagination.total}
|
||||
activePage={currentPage.page}
|
||||
perPage={currentPage.perPage}
|
||||
total={currentPage.total}
|
||||
layout={pagination.layout}
|
||||
maxButtons={pagination.maxButtons}
|
||||
perPageAvailable={pagination.perPageAvailable}
|
||||
popOverContainer={pagination.popOverContainer}
|
||||
popOverContainerSelector={pagination.popOverContainerSelector}
|
||||
onPageChange={onPageChange}
|
||||
onPageChange={this.onPageChangeHandle}
|
||||
/>
|
||||
</div>
|
||||
) : null;
|
||||
);
|
||||
}
|
||||
|
||||
renderSearchResult(props: TransferProps) {
|
||||
@ -761,7 +824,9 @@ export class Transfer<
|
||||
loadingConfig,
|
||||
checkAll,
|
||||
checkAllLabel,
|
||||
onlyChildren
|
||||
onlyChildren,
|
||||
autoCheckChildren = true,
|
||||
initiallyOpen = true
|
||||
} = props;
|
||||
|
||||
return selectMode === 'table' ? (
|
||||
@ -804,6 +869,8 @@ export class Transfer<
|
||||
loadingConfig={loadingConfig}
|
||||
checkAllLabel={checkAllLabel}
|
||||
checkAll={checkAll}
|
||||
initiallyOpen={initiallyOpen}
|
||||
autoCheckChildren={autoCheckChildren}
|
||||
/>
|
||||
) : selectMode === 'chained' ? (
|
||||
<ChainedSelection
|
||||
|
@ -23,10 +23,23 @@ export interface TransferPickerProps extends Omit<TransferProps, 'itemRender'> {
|
||||
popOverContainer?: any;
|
||||
}
|
||||
|
||||
export class TransferPicker extends React.Component<TransferPickerProps> {
|
||||
export interface TransferPickerState {
|
||||
tempValue?: any;
|
||||
}
|
||||
|
||||
export class TransferPicker extends React.Component<
|
||||
TransferPickerProps,
|
||||
TransferPickerState
|
||||
> {
|
||||
state: TransferPickerState = {
|
||||
tempValue: null
|
||||
};
|
||||
optionModified = false;
|
||||
@autobind
|
||||
handleConfirm(value: any) {
|
||||
this.setState({
|
||||
tempValue: null
|
||||
});
|
||||
this.props.onChange?.(value, this.optionModified);
|
||||
this.optionModified = false;
|
||||
}
|
||||
@ -38,6 +51,9 @@ export class TransferPicker extends React.Component<TransferPickerProps> {
|
||||
|
||||
@autobind
|
||||
onBlur() {
|
||||
this.setState({
|
||||
tempValue: null
|
||||
});
|
||||
this.props.onBlur?.();
|
||||
}
|
||||
|
||||
@ -56,9 +72,19 @@ export class TransferPicker extends React.Component<TransferPickerProps> {
|
||||
popOverContainer,
|
||||
maxTagCount,
|
||||
overflowTagPopover,
|
||||
placeholder,
|
||||
...rest
|
||||
} = this.props;
|
||||
|
||||
const tp = {
|
||||
value: this.state.tempValue || value,
|
||||
onChange: (value: any) => {
|
||||
this.setState({
|
||||
tempValue: value
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<PickerContainer
|
||||
title={__('Select.placeholder')}
|
||||
@ -84,13 +110,13 @@ export class TransferPicker extends React.Component<TransferPickerProps> {
|
||||
this.optionModified = true;
|
||||
setState({options, value});
|
||||
} else {
|
||||
onChange(value);
|
||||
tp.onChange(value);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
value={value}
|
||||
value={tp.value}
|
||||
onConfirm={this.handleConfirm}
|
||||
size={size}
|
||||
>
|
||||
@ -105,7 +131,7 @@ export class TransferPicker extends React.Component<TransferPickerProps> {
|
||||
result={value}
|
||||
onResultChange={onChange}
|
||||
onResultClick={onClick}
|
||||
placeholder={__('Select.placeholder')}
|
||||
placeholder={placeholder ?? __('Select.placeholder')}
|
||||
disabled={disabled}
|
||||
borderMode={borderMode}
|
||||
itemRender={option => (
|
||||
|
22
packages/amis/.swcrc
Normal file
22
packages/amis/.swcrc
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/swcrc",
|
||||
"jsc": {
|
||||
"parser": {
|
||||
"syntax": "typescript",
|
||||
"tsx": true,
|
||||
"decorators": true,
|
||||
"dynamicImport": true
|
||||
},
|
||||
"transform": {
|
||||
"decoratorMetadata": true,
|
||||
"legacyDecorator": true,
|
||||
"react": {
|
||||
"runtime": "classic"
|
||||
}
|
||||
},
|
||||
"keepClassNames": true,
|
||||
"externalHelpers": true,
|
||||
"loose": false
|
||||
},
|
||||
"minify": false
|
||||
}
|
@ -5,7 +5,8 @@ import {makeEnv, wait} from '../helper';
|
||||
|
||||
test('1. EventAction:dialog args', async () => {
|
||||
const notify = jest.fn();
|
||||
const {getByText, container}: any = render(
|
||||
let container: HTMLElement;
|
||||
const renderResult: any = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'page',
|
||||
@ -142,6 +143,8 @@ test('1. EventAction:dialog args', async () => {
|
||||
})
|
||||
)
|
||||
);
|
||||
const getByText = renderResult.getByText;
|
||||
container = renderResult.container;
|
||||
|
||||
// events
|
||||
fireEvent.click(getByText('打开弹窗'));
|
||||
@ -222,7 +225,8 @@ test('1. EventAction:dialog args', async () => {
|
||||
|
||||
test('2. EventAction:dialog', async () => {
|
||||
const notify = jest.fn();
|
||||
const {getByText, container}: any = render(
|
||||
let container: HTMLElement;
|
||||
const renderResult: any = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'page',
|
||||
@ -356,6 +360,9 @@ test('2. EventAction:dialog', async () => {
|
||||
)
|
||||
);
|
||||
|
||||
const getByText = renderResult.getByText;
|
||||
container = renderResult.container;
|
||||
|
||||
// events
|
||||
fireEvent.click(getByText('打开弹窗'));
|
||||
expect(container).toMatchSnapshot();
|
||||
@ -434,7 +441,8 @@ test('2. EventAction:dialog', async () => {
|
||||
}, 7000);
|
||||
|
||||
test('3. EventAction:dialog data', async () => {
|
||||
const {getByText, container}: any = render(
|
||||
let container: HTMLElement;
|
||||
const renderResult: any = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'page',
|
||||
@ -480,7 +488,8 @@ test('3. EventAction:dialog data', async () => {
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
const getByText = renderResult.getByText;
|
||||
container = renderResult.container;
|
||||
// events
|
||||
fireEvent.click(getByText('打开弹窗'));
|
||||
await waitFor(() => {
|
||||
@ -491,7 +500,8 @@ test('3. EventAction:dialog data', async () => {
|
||||
}, 7000);
|
||||
|
||||
test('4. EventAction:dialog data2', async () => {
|
||||
const {getByText, container}: any = render(
|
||||
let container: HTMLElement;
|
||||
const renderResult: any = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'page',
|
||||
@ -535,6 +545,8 @@ test('4. EventAction:dialog data2', async () => {
|
||||
})
|
||||
)
|
||||
);
|
||||
const getByText = renderResult.getByText;
|
||||
container = renderResult.container;
|
||||
|
||||
// events
|
||||
fireEvent.click(getByText('打开弹窗'));
|
||||
@ -642,6 +654,7 @@ test('4. EventAction:dialog data2', async () => {
|
||||
|
||||
test('5. EventAction:dialog formitem without form', async () => {
|
||||
const onAction = jest.fn();
|
||||
let portal: any = null;
|
||||
const {getByText, container}: any = render(
|
||||
amisRender(
|
||||
{
|
||||
@ -689,11 +702,13 @@ test('5. EventAction:dialog formitem without form', async () => {
|
||||
},
|
||||
{},
|
||||
makeEnv({
|
||||
getModalContainer: () => container
|
||||
getModalContainer: () => portal
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
portal = container;
|
||||
await wait(200);
|
||||
const button = getByText('Dialog');
|
||||
fireEvent.click(button);
|
||||
await wait(200);
|
||||
|
@ -5,7 +5,8 @@ import {makeEnv, wait} from '../helper';
|
||||
|
||||
test('EventAction:drawer args', async () => {
|
||||
const notify = jest.fn();
|
||||
const {getByText, container}: any = render(
|
||||
let container: HTMLElement;
|
||||
const renderResult: any = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'page',
|
||||
@ -142,6 +143,8 @@ test('EventAction:drawer args', async () => {
|
||||
})
|
||||
)
|
||||
);
|
||||
const getByText = renderResult.getByText;
|
||||
container = renderResult.container;
|
||||
|
||||
// events
|
||||
fireEvent.click(getByText('打开抽屉'));
|
||||
@ -222,7 +225,8 @@ test('EventAction:drawer args', async () => {
|
||||
|
||||
test('EventAction:drawer', async () => {
|
||||
const notify = jest.fn();
|
||||
const {getByText, container}: any = render(
|
||||
let container: HTMLElement;
|
||||
const renderResult: any = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'page',
|
||||
@ -356,6 +360,9 @@ test('EventAction:drawer', async () => {
|
||||
)
|
||||
);
|
||||
|
||||
const getByText = renderResult.getByText;
|
||||
container = renderResult.container;
|
||||
|
||||
// events
|
||||
fireEvent.click(getByText('打开抽屉'));
|
||||
expect(container).toMatchSnapshot();
|
||||
@ -434,7 +441,8 @@ test('EventAction:drawer', async () => {
|
||||
}, 7000);
|
||||
|
||||
test('EventAction:drawer data', async () => {
|
||||
const {getByText, container}: any = render(
|
||||
let container: HTMLElement;
|
||||
const renderResult: any = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'page',
|
||||
@ -480,6 +488,8 @@ test('EventAction:drawer data', async () => {
|
||||
})
|
||||
)
|
||||
);
|
||||
const getByText = renderResult.getByText;
|
||||
container = renderResult.container;
|
||||
|
||||
// events
|
||||
fireEvent.click(getByText('打开抽屉'));
|
||||
@ -491,7 +501,8 @@ test('EventAction:drawer data', async () => {
|
||||
}, 7000);
|
||||
|
||||
test('EventAction:drawer data2', async () => {
|
||||
const {getByText, container}: any = render(
|
||||
let container: HTMLElement;
|
||||
const renderResult: any = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'page',
|
||||
@ -536,6 +547,9 @@ test('EventAction:drawer data2', async () => {
|
||||
)
|
||||
);
|
||||
|
||||
const getByText = renderResult.getByText;
|
||||
container = renderResult.container;
|
||||
|
||||
// events
|
||||
fireEvent.click(getByText('打开抽屉'));
|
||||
await waitFor(() => {
|
||||
|
@ -16,7 +16,8 @@ test('EventAction:prevent', async () => {
|
||||
}
|
||||
})
|
||||
);
|
||||
const {getByText, container}: any = render(
|
||||
let container: HTMLElement;
|
||||
const renderResult: any = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'page',
|
||||
@ -84,6 +85,8 @@ test('EventAction:prevent', async () => {
|
||||
})
|
||||
)
|
||||
);
|
||||
const getByText = renderResult.getByText;
|
||||
container = renderResult.container;
|
||||
|
||||
fireEvent.click(getByText('打开弹窗'));
|
||||
await waitFor(() => {
|
||||
@ -111,7 +114,8 @@ test('EventAction:ignoreError', async () => {
|
||||
}
|
||||
})
|
||||
);
|
||||
const {getByText, container}: any = render(
|
||||
let container: HTMLElement;
|
||||
const renderResult: any = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'page',
|
||||
@ -156,6 +160,8 @@ test('EventAction:ignoreError', async () => {
|
||||
})
|
||||
)
|
||||
);
|
||||
const getByText = renderResult.getByText;
|
||||
container = renderResult.container;
|
||||
|
||||
fireEvent.click(getByText('按钮'));
|
||||
await waitFor(() => {
|
||||
|
@ -0,0 +1,85 @@
|
||||
import {fireEvent, render} from '@testing-library/react';
|
||||
import '../../../src';
|
||||
import {render as amisRender} from '../../../src';
|
||||
import {makeEnv, wait} from '../../helper';
|
||||
|
||||
test('paginationWrapper: service + crud', async () => {
|
||||
const fetcher = jest.fn().mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
data: {
|
||||
status: 0,
|
||||
data: {
|
||||
items: [
|
||||
{
|
||||
label: '110101',
|
||||
name: '东城区',
|
||||
sale: 46861
|
||||
},
|
||||
{
|
||||
label: '110102',
|
||||
name: '西城区',
|
||||
sale: 44882
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
const {container} = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'page',
|
||||
body: [
|
||||
{
|
||||
type: 'service',
|
||||
id: 'u:ff652047d747',
|
||||
api: {
|
||||
method: 'get',
|
||||
url: 'https://yapi.baidu-int.com/mock/42601/amis-chart/chart/sales/data2'
|
||||
},
|
||||
body: [
|
||||
{
|
||||
type: 'pagination-wrapper',
|
||||
body: [
|
||||
{
|
||||
type: 'crud',
|
||||
source: '${items}',
|
||||
columns: [
|
||||
{
|
||||
name: 'label',
|
||||
label: '地区',
|
||||
type: 'text',
|
||||
id: 'u:331ab3342710'
|
||||
},
|
||||
{
|
||||
name: 'sale',
|
||||
label: '销售',
|
||||
type: 'text',
|
||||
id: 'u:3dba120eda1d'
|
||||
}
|
||||
],
|
||||
id: 'u:b3c77cb44fc8',
|
||||
perPageAvailable: [10]
|
||||
}
|
||||
],
|
||||
inputName: 'items',
|
||||
outputName: 'items',
|
||||
perPage: 20,
|
||||
position: 'bottom'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{},
|
||||
makeEnv({
|
||||
fetcher
|
||||
})
|
||||
)
|
||||
);
|
||||
await wait(200);
|
||||
const tds = [].slice
|
||||
.call(container.querySelectorAll('tbody td'))
|
||||
.map((td: any) => td.textContent);
|
||||
expect(tds).toEqual(['110101', '46861', '110102', '44882']);
|
||||
});
|
104
packages/amis/__tests__/renderers/App.test.tsx
Normal file
104
packages/amis/__tests__/renderers/App.test.tsx
Normal file
@ -0,0 +1,104 @@
|
||||
import React from 'react';
|
||||
import Action from '../../src/renderers/Action';
|
||||
import * as renderer from 'react-test-renderer';
|
||||
import {
|
||||
render,
|
||||
fireEvent,
|
||||
cleanup,
|
||||
screen,
|
||||
waitFor,
|
||||
within
|
||||
} from '@testing-library/react';
|
||||
import {render as amisRender} from '../../src';
|
||||
import {makeEnv, wait} from '../helper';
|
||||
import '../../src';
|
||||
|
||||
afterEach(cleanup);
|
||||
|
||||
// 关联 issue https://github.com/baidu/amis/issues/9564
|
||||
test('Renderers:App locale', async () => {
|
||||
const fetcher = jest.fn().mockImplementation((api, options) => {
|
||||
if (api.url.startsWith('/pageList')) {
|
||||
return Promise.resolve({
|
||||
status: 200,
|
||||
data: {
|
||||
status: 0,
|
||||
msg: '',
|
||||
data: {
|
||||
pages: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
'label': 'Home',
|
||||
'icon': 'fa fa-home',
|
||||
'url': '/admin/page/home',
|
||||
'schemaApi': '/pageDetail',
|
||||
'isDefaultPage': true,
|
||||
'sort': 100,
|
||||
'zh-CN': {
|
||||
label: '首页'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
});
|
||||
} else if (api.url.startsWith('/pageDetail')) {
|
||||
return Promise.resolve({
|
||||
status: 200,
|
||||
data: {
|
||||
type: 'page',
|
||||
body: [
|
||||
{
|
||||
'type': 'input-text',
|
||||
'name': 'a',
|
||||
'label': 'dev',
|
||||
'content': 'False',
|
||||
'zh-CN': {
|
||||
label: '开发环境'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.resolve({
|
||||
status: 200,
|
||||
data: {
|
||||
status: 404,
|
||||
msg: 'notFound'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const {container, getByText} = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'app',
|
||||
api: {
|
||||
method: 'get',
|
||||
url: '/pageList'
|
||||
}
|
||||
},
|
||||
{
|
||||
locale: 'zh-CN'
|
||||
},
|
||||
makeEnv({
|
||||
fetcher
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
await wait(500);
|
||||
|
||||
const link = container.querySelector('nav li span');
|
||||
expect(link).toBeInTheDocument();
|
||||
expect(link!.textContent).toBe('首页');
|
||||
|
||||
const inputLabel = container.querySelector('.cxd-Form-label');
|
||||
expect(inputLabel).toBeInTheDocument();
|
||||
expect(inputLabel!.textContent).toBe('开发环境');
|
||||
});
|
@ -193,7 +193,8 @@ test('CRUD reload dialog1', async () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
const {container, getByText}: any = render(
|
||||
let container: HTMLElement;
|
||||
const renderResult: any = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'page',
|
||||
@ -244,6 +245,8 @@ test('CRUD reload dialog1', async () => {
|
||||
makeEnv({fetcher: mockFetcher, getModalContainer: () => container})
|
||||
)
|
||||
);
|
||||
const getByText = renderResult.getByText;
|
||||
container = renderResult.container;
|
||||
await wait(200);
|
||||
const saveBtn = container.querySelectorAll('tbody>tr button')[0];
|
||||
expect(saveBtn).toBeTruthy();
|
||||
@ -287,7 +290,8 @@ test('CRUD reload dialog2', async () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
const {container, getByText}: any = render(
|
||||
let container: HTMLElement;
|
||||
const renderResult: any = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'page',
|
||||
@ -339,6 +343,8 @@ test('CRUD reload dialog2', async () => {
|
||||
makeEnv({fetcher: mockFetcher, getModalContainer: () => container})
|
||||
)
|
||||
);
|
||||
const getByText = renderResult.getByText;
|
||||
container = renderResult.container;
|
||||
await wait(200);
|
||||
const saveBtn = container.querySelectorAll('tbody>tr button')[0];
|
||||
expect(saveBtn).toBeTruthy();
|
||||
@ -378,7 +384,8 @@ test('CRUD reload drawer1', async () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
const {container, getByText}: any = render(
|
||||
let container: HTMLElement;
|
||||
const renderResult: any = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'page',
|
||||
@ -429,6 +436,8 @@ test('CRUD reload drawer1', async () => {
|
||||
makeEnv({fetcher: mockFetcher, getModalContainer: () => container})
|
||||
)
|
||||
);
|
||||
const getByText = renderResult.getByText;
|
||||
container = renderResult.container;
|
||||
await wait(200);
|
||||
const saveBtn = container.querySelectorAll('tbody>tr button')[0];
|
||||
expect(saveBtn).toBeTruthy();
|
||||
@ -472,7 +481,8 @@ test('CRUD reload drawer2', async () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
const {container, getByText}: any = render(
|
||||
let container: HTMLElement;
|
||||
const renderResult: any = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'page',
|
||||
@ -524,6 +534,8 @@ test('CRUD reload drawer2', async () => {
|
||||
makeEnv({fetcher: mockFetcher, getModalContainer: () => container})
|
||||
)
|
||||
);
|
||||
const getByText = renderResult.getByText;
|
||||
container = renderResult.container;
|
||||
await wait(200);
|
||||
const saveBtn = container.querySelectorAll('tbody>tr button')[0];
|
||||
expect(saveBtn).toBeTruthy();
|
||||
|
@ -162,7 +162,8 @@ test('Picker filter1', async () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
const {container} = render(
|
||||
let container: HTMLElement;
|
||||
const renderResult: any = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'page',
|
||||
@ -217,6 +218,8 @@ test('Picker filter1', async () => {
|
||||
makeEnv({fetcher: mockFetcher, getModalContainer: () => container} as any)
|
||||
)
|
||||
);
|
||||
container = renderResult.container;
|
||||
|
||||
await wait(200);
|
||||
const pickerBtn = container.querySelector('span.cxd-Picker-btn')!;
|
||||
expect(pickerBtn).toBeTruthy();
|
||||
@ -249,7 +252,8 @@ test('Picker filter2', async () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
const {container} = render(
|
||||
let container: HTMLElement;
|
||||
const renderResult: any = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'page',
|
||||
@ -295,6 +299,8 @@ test('Picker filter2', async () => {
|
||||
makeEnv({fetcher: mockFetcher, getModalContainer: () => container} as any)
|
||||
)
|
||||
);
|
||||
container = renderResult.container;
|
||||
|
||||
await wait(200);
|
||||
const pickerBtn = container.querySelector('span.cxd-Picker-btn')!;
|
||||
expect(pickerBtn).toBeTruthy();
|
||||
|
@ -291,7 +291,7 @@ exports[`Renderer:inputCity with searchable: open select 1`] = `
|
||||
<div
|
||||
class="cxd-PopOver cxd-Select-popover cxd-PopOver--leftBottomLeftTop cxd-PopOver--v-top"
|
||||
role="popover"
|
||||
style="display: block; width: auto; left: 0px; top: 0px; position: relative;"
|
||||
style="display: block; width: auto; left: 1024px; top: 768px; position: relative;"
|
||||
theme="cxd"
|
||||
>
|
||||
<div
|
||||
|
@ -1,257 +1,5 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Renderer:input-formula 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="cxd-Page"
|
||||
>
|
||||
<div
|
||||
class="cxd-Page-content"
|
||||
>
|
||||
<div
|
||||
class="cxd-Page-main"
|
||||
>
|
||||
<div
|
||||
class="cxd-Page-body"
|
||||
role="page-body"
|
||||
>
|
||||
<div
|
||||
class="cxd-Panel cxd-Panel--default cxd-Panel--form"
|
||||
>
|
||||
<div
|
||||
class="cxd-Panel-heading"
|
||||
>
|
||||
<h3
|
||||
class="cxd-Panel-title"
|
||||
>
|
||||
<span
|
||||
class="cxd-TplField"
|
||||
>
|
||||
<span>
|
||||
表单
|
||||
</span>
|
||||
</span>
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
class="cxd-Panel-body"
|
||||
>
|
||||
<form
|
||||
class="cxd-Form cxd-Form--normal"
|
||||
novalidate=""
|
||||
>
|
||||
<input
|
||||
style="display: none;"
|
||||
type="submit"
|
||||
/>
|
||||
<div
|
||||
class="cxd-JsonField cxd-Form--debug"
|
||||
>
|
||||
<div
|
||||
class="react-json-view"
|
||||
style="font-family: monospace; cursor: default; background-color: rgba(0, 0, 0, 0); position: relative;"
|
||||
>
|
||||
<div
|
||||
class="pretty-json-container object-container"
|
||||
>
|
||||
<div
|
||||
class="object-content"
|
||||
>
|
||||
<div
|
||||
class="object-key-val"
|
||||
>
|
||||
<span>
|
||||
<span
|
||||
style="display: inline-block; cursor: pointer;"
|
||||
>
|
||||
<div
|
||||
class="icon-container"
|
||||
style="display: inline-block; width: 17px;"
|
||||
>
|
||||
<span
|
||||
class="expanded-icon"
|
||||
>
|
||||
<svg
|
||||
fill="#586e75"
|
||||
height="1em"
|
||||
style="vertical-align: middle; color: rgb(88, 110, 117); height: 1em; width: 1em;"
|
||||
viewBox="0 0 1792 1792"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M1344 800v64q0 14-9 23t-23 9h-832q-14 0-23-9t-9-23v-64q0-14 9-23t23-9h832q14 0 23 9t9 23zm128 448v-832q0-66-47-113t-113-47h-832q-66 0-113 47t-47 113v832q0 66 47 113t113 47h832q66 0 113-47t47-113zm128-832v832q0 119-84.5 203.5t-203.5 84.5h-832q-119 0-203.5-84.5t-84.5-203.5v-832q0-119 84.5-203.5t203.5-84.5h832q119 0 203.5 84.5t84.5 203.5z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
<span />
|
||||
<span
|
||||
style="display: inline-block; cursor: pointer; font-weight: bold; color: rgb(0, 43, 54);"
|
||||
>
|
||||
{
|
||||
</span>
|
||||
</span>
|
||||
<div
|
||||
class="object-meta-data"
|
||||
style="display: inline-block; padding: 0px 0px 0px 10px;"
|
||||
>
|
||||
<span
|
||||
class="object-size"
|
||||
style="color: rgba(0, 0, 0, 0.3); border-radius: 3px; font-style: italic; margin: 0px 6px 0px 0px; cursor: default;"
|
||||
>
|
||||
1
|
||||
item
|
||||
</span>
|
||||
</div>
|
||||
</span>
|
||||
<div
|
||||
class="pushed-content object-container"
|
||||
>
|
||||
<div
|
||||
class="object-content"
|
||||
style="margin-left: 6px;"
|
||||
>
|
||||
<div
|
||||
class="variable-row"
|
||||
style="border-left: 1px solid rgb(235, 235, 235); padding: 3px 5px 3px 20px;"
|
||||
>
|
||||
<span>
|
||||
<span
|
||||
class="object-key"
|
||||
style="display: inline-block; color: rgb(0, 43, 54); letter-spacing: 0.5px; font-style: none; vertical-align: top; opacity: 0.85;"
|
||||
>
|
||||
<span
|
||||
style="vertical-align: top;"
|
||||
>
|
||||
"
|
||||
</span>
|
||||
<span
|
||||
style="display: inline-block;"
|
||||
>
|
||||
formula
|
||||
</span>
|
||||
<span
|
||||
style="vertical-align: top;"
|
||||
>
|
||||
"
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
style="display: inline-block; margin: 0px 5px; color: rgb(0, 43, 54); vertical-align: top;"
|
||||
>
|
||||
:
|
||||
</span>
|
||||
</span>
|
||||
<div
|
||||
class="variable-value"
|
||||
style="display: inline-block; padding-right: 6px; position: relative; cursor: default;"
|
||||
>
|
||||
<div
|
||||
style="display: inline-block; color: rgb(203, 75, 22);"
|
||||
>
|
||||
<span
|
||||
class="string-value"
|
||||
style="cursor: default;"
|
||||
>
|
||||
"
|
||||
SUM(1 + 2)
|
||||
"
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span
|
||||
class="brace-row"
|
||||
>
|
||||
<span
|
||||
style="display: inline-block; cursor: pointer; font-weight: bold; color: rgb(0, 43, 54); padding-left: 3px;"
|
||||
>
|
||||
}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="cxd-Form-item cxd-Form-item--normal"
|
||||
data-role="form-item"
|
||||
>
|
||||
<label
|
||||
class="cxd-Form-label"
|
||||
>
|
||||
<span>
|
||||
<span
|
||||
class="cxd-TplField"
|
||||
>
|
||||
<span>
|
||||
公式
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
<div
|
||||
class="cxd-FormulaPicker cxd-FormulaPicker--text cxd-Form-control"
|
||||
>
|
||||
<div
|
||||
class="cxd-ResultBox cxd-FormulaPicker-input cxd-ResultBox--borderFull"
|
||||
tabindex="-1"
|
||||
>
|
||||
<div
|
||||
class="cxd-ResultBox-value-wrap"
|
||||
>
|
||||
<input
|
||||
class="cxd-ResultBox-value-input"
|
||||
placeholder="暂无数据"
|
||||
theme="cxd"
|
||||
type="text"
|
||||
value="SUM(1 + 2)"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="cxd-ResultBox-actions"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
class="cxd-Button cxd-Button--default cxd-Button--size-default cxd-FormulaPicker-action"
|
||||
type="button"
|
||||
>
|
||||
<icon-mock
|
||||
classname="cxd-FormulaPicker-icon icon is-filled icon-function"
|
||||
icon="function"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div
|
||||
class="cxd-Panel-footerWrap"
|
||||
>
|
||||
<div
|
||||
class="cxd-Panel-btnToolbar cxd-Panel-footer"
|
||||
>
|
||||
<button
|
||||
class="cxd-Button cxd-Button--primary cxd-Button--size-default"
|
||||
type="submit"
|
||||
>
|
||||
<span>
|
||||
提交
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Renderer:input-formula button 1`] = `
|
||||
<div>
|
||||
<div
|
||||
|
@ -448,7 +448,7 @@ exports[`Renderer:input table add 1`] = `
|
||||
<th
|
||||
class="is-sticky is-sticky-right is-sticky-first-right cxd-Table-operationCell"
|
||||
data-index="5"
|
||||
style="right: 0px;"
|
||||
style="width: 150px; min-width: 150px;"
|
||||
>
|
||||
<div
|
||||
class="cxd-TableCell--title v-middle nowrap"
|
||||
|
@ -587,7 +587,7 @@ exports[`Renderer:InputTag InputTag with options 1`] = `
|
||||
<div
|
||||
class="cxd-PopOver cxd-TagControl-popover cxd-PopOver--leftBottomLeftTop cxd-PopOver--v-top"
|
||||
role="popover"
|
||||
style="display: block; left: 0px; top: 0px; position: relative;"
|
||||
style="display: block; left: 1024px; top: 768px; position: relative;"
|
||||
theme="cxd"
|
||||
>
|
||||
<div
|
||||
|
@ -209,7 +209,7 @@ exports[`Renderer:repeat 1`] = `
|
||||
<div
|
||||
class="cxd-PopOver cxd-Select-popover cxd-PopOver--leftBottomLeftTop cxd-PopOver--v-top"
|
||||
role="popover"
|
||||
style="display: block; width: 0px; left: 0px; top: 0px; position: relative;"
|
||||
style="display: block; width: 0px; left: 1024px; top: 768px; position: relative;"
|
||||
theme="cxd"
|
||||
>
|
||||
<div
|
||||
|
@ -356,7 +356,7 @@ exports[`Renderer:select associated mode with virtual 1`] = `
|
||||
<div
|
||||
class="cxd-PopOver cxd-TransferDropDown-popover cxd-PopOver--leftBottomLeftTop cxd-PopOver--v-top"
|
||||
role="popover"
|
||||
style="display: block; min-width: 100px; left: 0px; top: 0px; position: relative;"
|
||||
style="display: block; min-width: 100px; left: 1024px; top: 768px; position: relative;"
|
||||
theme="cxd"
|
||||
>
|
||||
<div
|
||||
@ -970,7 +970,7 @@ exports[`Renderer:select chained mode with virtual 1`] = `
|
||||
<div
|
||||
class="cxd-PopOver cxd-TransferDropDown-popover cxd-PopOver--leftBottomLeftTop cxd-PopOver--v-top"
|
||||
role="popover"
|
||||
style="display: block; min-width: 100px; left: 0px; top: 0px; position: relative;"
|
||||
style="display: block; min-width: 100px; left: 1024px; top: 768px; position: relative;"
|
||||
theme="cxd"
|
||||
>
|
||||
<div
|
||||
@ -1516,7 +1516,7 @@ exports[`Renderer:select group mode with virtual 1`] = `
|
||||
<div
|
||||
class="cxd-PopOver cxd-TransferDropDown-popover cxd-PopOver--leftBottomLeftTop cxd-PopOver--v-top"
|
||||
role="popover"
|
||||
style="display: block; min-width: 100px; left: 0px; top: 0px; position: relative;"
|
||||
style="display: block; min-width: 100px; left: 1024px; top: 768px; position: relative;"
|
||||
theme="cxd"
|
||||
>
|
||||
<div
|
||||
@ -2084,7 +2084,7 @@ exports[`Renderer:select table mode with virtual 1`] = `
|
||||
<div
|
||||
class="cxd-PopOver cxd-TransferDropDown-popover cxd-PopOver--leftBottomLeftTop cxd-PopOver--v-top"
|
||||
role="popover"
|
||||
style="display: block; min-width: 100px; left: 0px; top: 0px; position: relative;"
|
||||
style="display: block; min-width: 100px; left: 1024px; top: 768px; position: relative;"
|
||||
theme="cxd"
|
||||
>
|
||||
<div
|
||||
@ -2458,7 +2458,7 @@ exports[`Renderer:select table with labelField & valueField 1`] = `
|
||||
<div
|
||||
class="cxd-PopOver cxd-TransferDropDown-popover cxd-PopOver--leftBottomLeftTop cxd-PopOver--v-top"
|
||||
role="popover"
|
||||
style="display: block; min-width: 100px; left: 0px; top: 0px; position: relative;"
|
||||
style="display: block; min-width: 100px; left: 1024px; top: 768px; position: relative;"
|
||||
theme="cxd"
|
||||
>
|
||||
<div
|
||||
@ -2956,7 +2956,7 @@ exports[`Renderer:select virtual 1`] = `
|
||||
<div
|
||||
class="cxd-PopOver cxd-Select-popover cxd-PopOver--leftBottomLeftTop cxd-PopOver--v-top"
|
||||
role="popover"
|
||||
style="display: block; width: auto; left: 0px; top: 0px; position: relative;"
|
||||
style="display: block; width: auto; left: 1024px; top: 768px; position: relative;"
|
||||
theme="cxd"
|
||||
>
|
||||
<div
|
||||
|
@ -1579,7 +1579,7 @@ exports[`Renderer:text with options and multiple Renderer:text with options and
|
||||
<div
|
||||
class="cxd-PopOver cxd-TextControl-popover cxd-PopOver--leftBottomLeftTop cxd-PopOver--v-top"
|
||||
role="popover"
|
||||
style="display: block; width: 0px; left: 0px; top: 0px; position: relative;"
|
||||
style="display: block; width: 0px; left: 1024px; top: 768px; position: relative;"
|
||||
theme="cxd"
|
||||
>
|
||||
<div
|
||||
@ -1811,7 +1811,7 @@ exports[`Renderer:text with options and multiple Renderer:text with options and
|
||||
<div
|
||||
class="cxd-PopOver cxd-TextControl-popover cxd-PopOver--leftBottomLeftTop cxd-PopOver--v-top"
|
||||
role="popover"
|
||||
style="display: block; width: 0px; left: 0px; top: 0px; position: relative;"
|
||||
style="display: block; width: 0px; left: 1024px; top: 768px; position: relative;"
|
||||
theme="cxd"
|
||||
>
|
||||
<div
|
||||
@ -2070,7 +2070,7 @@ exports[`Renderer:text with options and multiple Renderer:text with options and
|
||||
<div
|
||||
class="cxd-PopOver cxd-TextControl-popover cxd-PopOver--leftBottomLeftTop cxd-PopOver--v-top"
|
||||
role="popover"
|
||||
style="display: block; width: 0px; left: 0px; top: 0px; position: relative;"
|
||||
style="display: block; width: 0px; left: 1024px; top: 768px; position: relative;"
|
||||
theme="cxd"
|
||||
>
|
||||
<div
|
||||
@ -2328,7 +2328,7 @@ exports[`Renderer:text with options and multiple Renderer:text with options and
|
||||
<div
|
||||
class="cxd-PopOver cxd-TextControl-popover cxd-PopOver--leftBottomLeftTop cxd-PopOver--v-top"
|
||||
role="popover"
|
||||
style="display: block; width: 0px; left: 0px; top: 0px; position: relative;"
|
||||
style="display: block; width: 0px; left: 1024px; top: 768px; position: relative;"
|
||||
theme="cxd"
|
||||
>
|
||||
<div
|
||||
@ -2699,7 +2699,7 @@ exports[`Renderer:text with options: options is open 1`] = `
|
||||
<div
|
||||
class="cxd-PopOver cxd-TextControl-popover cxd-PopOver--leftBottomLeftTop cxd-PopOver--v-top"
|
||||
role="popover"
|
||||
style="display: block; width: 0px; left: 0px; top: 0px; position: relative;"
|
||||
style="display: block; width: 0px; left: 1024px; top: 768px; position: relative;"
|
||||
theme="cxd"
|
||||
>
|
||||
<div
|
||||
|
@ -11,7 +11,8 @@ afterEach(() => {
|
||||
});
|
||||
|
||||
test('Renderer:button', async () => {
|
||||
const {getByText, container}: any = render(
|
||||
let container: HTMLElement;
|
||||
const renderResult: any = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'form',
|
||||
@ -55,6 +56,8 @@ test('Renderer:button', async () => {
|
||||
})
|
||||
)
|
||||
);
|
||||
const getByText = renderResult.getByText;
|
||||
container = renderResult.container;
|
||||
expect(container).toMatchSnapshot();
|
||||
fireEvent.click(getByText(/OpenDialog/));
|
||||
await wait(300);
|
||||
|
@ -16,7 +16,8 @@ afterEach(() => {
|
||||
});
|
||||
|
||||
test('Renderer:button-toolbar', async () => {
|
||||
const {getByText, container}: any = render(
|
||||
let container: HTMLElement;
|
||||
const renderResult: any = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'form',
|
||||
@ -55,6 +56,8 @@ test('Renderer:button-toolbar', async () => {
|
||||
})
|
||||
)
|
||||
);
|
||||
const getByText = renderResult.getByText;
|
||||
container = renderResult.container;
|
||||
expect(container).toMatchSnapshot();
|
||||
fireEvent.click(getByText(/OpenDialog/));
|
||||
await wait(300);
|
||||
|
@ -509,7 +509,14 @@ test('Renderer:inputDate disabledDate', async () => {
|
||||
)!;
|
||||
expect(todayCell).toBeInTheDocument();
|
||||
|
||||
const toddayTr = todayCell.parentElement as HTMLElement;
|
||||
const toddayTr: HTMLElement = // 因为周日被认为是第一天
|
||||
// 当今天是周日的时候,moment().day(1) 是明天,moment().day(2) 是后天
|
||||
// 而日历组件周日是最后一天,所以 moment().day(1) 其实是在下一组里面展示的
|
||||
(
|
||||
moment().day() === 0
|
||||
? todayCell.parentElement?.nextElementSibling
|
||||
: todayCell.parentElement
|
||||
) as any;
|
||||
|
||||
const mondayCell = toddayTr.querySelector(
|
||||
'td[data-value="' + monday.date() + '"]'
|
||||
@ -540,9 +547,8 @@ test('Renderer:inputDate defaultValue with formula', async () => {
|
||||
|
||||
expect(input).toBeInTheDocument();
|
||||
expect(input.value).toBe('2021-12-06');
|
||||
|
||||
});
|
||||
|
||||
|
||||
test('Renderer:inputDate setValue actions with special words', async () => {
|
||||
const {container, submitBtn, onSubmit, getByText} = await setup([
|
||||
{
|
||||
|
@ -78,10 +78,13 @@ test('Renderer:input-formula', async () => {
|
||||
)
|
||||
);
|
||||
|
||||
await wait(500);
|
||||
expect(container).toMatchSnapshot();
|
||||
// await wait(500);
|
||||
|
||||
await findByDisplayValue('SUM(1 + 2)');
|
||||
|
||||
// TODO: 不知道为啥切换到 @swc/jest 后不支持
|
||||
// expect(container).toMatchSnapshot();
|
||||
|
||||
// TODO: 貌似 jsdom 不支持 codemirror,进行不下去了
|
||||
|
||||
// const action = document.querySelector('button.cxd-FormulaPicker-action');
|
||||
|
@ -809,3 +809,213 @@ test('Renderer:input-table formula', async () => {
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
// 对应 github issue: https://github.com/baidu/amis/issues/9494
|
||||
test('Renderer:input-table autoFill', async () => {
|
||||
const onSubmit = jest.fn();
|
||||
const {container} = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'page',
|
||||
title: 'Hello low code',
|
||||
body: [
|
||||
{
|
||||
type: 'form',
|
||||
api: '/api/mock2/form/saveForm',
|
||||
body: [
|
||||
{
|
||||
type: 'input-table',
|
||||
name: 'table',
|
||||
label: '表格表单',
|
||||
columns: [
|
||||
{
|
||||
label: '名称',
|
||||
name: 'name',
|
||||
quickEdit: {
|
||||
type: 'input-text',
|
||||
name: 'name',
|
||||
id: 'u:514910e73695'
|
||||
},
|
||||
id: 'u:97d119520d7c'
|
||||
},
|
||||
{
|
||||
label: '分数',
|
||||
name: 'score',
|
||||
quickEdit: {
|
||||
type: 'input-number',
|
||||
name: 'score',
|
||||
id: 'u:644f5984ff07'
|
||||
},
|
||||
id: 'u:60636ff9ed10'
|
||||
},
|
||||
{
|
||||
label: '等级',
|
||||
name: 'level',
|
||||
quickEdit: {
|
||||
type: 'select',
|
||||
name: 'level',
|
||||
autoFill: {
|
||||
id: '$id'
|
||||
},
|
||||
id: 'u:38014752298b',
|
||||
options: [
|
||||
{
|
||||
label: 'a',
|
||||
value: '111',
|
||||
id: 111
|
||||
},
|
||||
{
|
||||
label: 'a1',
|
||||
value: '1121',
|
||||
id: 222
|
||||
}
|
||||
]
|
||||
},
|
||||
id: 'u:bc682229ad4f'
|
||||
}
|
||||
],
|
||||
addable: true,
|
||||
footerAddBtn: {
|
||||
label: '新增',
|
||||
icon: 'fa fa-plus',
|
||||
id: 'u:a0d2d9eab4f7'
|
||||
},
|
||||
strictMode: true,
|
||||
id: 'u:c296ba75753c',
|
||||
minLength: 0,
|
||||
editable: true,
|
||||
removable: true
|
||||
}
|
||||
],
|
||||
id: 'u:a2f24ee3ab2d',
|
||||
debug: true
|
||||
}
|
||||
],
|
||||
id: 'u:09eedced8bb6',
|
||||
asideResizor: false,
|
||||
style: {
|
||||
boxShadow: ' 0px 0px 0px 0px transparent'
|
||||
},
|
||||
pullRefresh: {
|
||||
disabled: true
|
||||
}
|
||||
},
|
||||
{
|
||||
onSubmit: onSubmit
|
||||
},
|
||||
makeEnv({})
|
||||
)
|
||||
);
|
||||
|
||||
await wait(200);
|
||||
|
||||
const add = container.querySelector('.cxd-InputTable-toolbar button');
|
||||
fireEvent.click(add!);
|
||||
await wait(200);
|
||||
|
||||
fireEvent.change(container.querySelector('input[name="name"]')!, {
|
||||
target: {value: 'a1'}
|
||||
});
|
||||
await wait(200);
|
||||
|
||||
fireEvent.change(container.querySelector('input[name="score"]')!, {
|
||||
target: {value: '123'}
|
||||
});
|
||||
await wait(200);
|
||||
|
||||
fireEvent.click(container.querySelector('.cxd-Select')!);
|
||||
await wait(200);
|
||||
fireEvent.click(container.querySelector('.cxd-Select-menu [role="option"]')!);
|
||||
await wait(200);
|
||||
|
||||
fireEvent.click(container.querySelector('.cxd-OperationField button')!);
|
||||
await wait(200);
|
||||
|
||||
const submitBtn = container.querySelector('button[type=submit]');
|
||||
fireEvent.click(submitBtn!);
|
||||
await wait(200);
|
||||
|
||||
expect(onSubmit).toBeCalled();
|
||||
expect(onSubmit.mock.calls[0][0]).toEqual({
|
||||
table: [
|
||||
{
|
||||
id: 111,
|
||||
name: 'a1',
|
||||
score: 123,
|
||||
level: '111'
|
||||
}
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
// 对应 github issue: https://github.com/baidu/amis/issues/9520
|
||||
test('Renderer:input-table canAccessSuperData', async () => {
|
||||
const onSubmit = jest.fn();
|
||||
const {container} = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'page',
|
||||
body: {
|
||||
type: 'form',
|
||||
data: {
|
||||
a: 'xxx',
|
||||
table: [
|
||||
{
|
||||
a: 'a1',
|
||||
b: 'b1'
|
||||
}
|
||||
]
|
||||
},
|
||||
api: '/amis/api/mock2/form/saveForm',
|
||||
body: [
|
||||
{
|
||||
showIndex: true,
|
||||
type: 'input-table',
|
||||
name: 'table',
|
||||
addable: true,
|
||||
needConfirm: true,
|
||||
columns: [
|
||||
{
|
||||
name: 'a',
|
||||
label: 'A',
|
||||
type: 'wrapper',
|
||||
body: [
|
||||
{
|
||||
name: 'a',
|
||||
label: false,
|
||||
type: 'input-text'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'b',
|
||||
label: 'B',
|
||||
type: 'input-text'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{},
|
||||
makeEnv({})
|
||||
)
|
||||
);
|
||||
|
||||
await wait(200);
|
||||
const addBtn = container.querySelector('.cxd-OperationField button');
|
||||
expect(addBtn).toBeInTheDocument();
|
||||
fireEvent.click(addBtn!);
|
||||
|
||||
await wait(200);
|
||||
const confrimBtn = container.querySelector('.cxd-OperationField button');
|
||||
expect(confrimBtn).toBeInTheDocument();
|
||||
fireEvent.click(confrimBtn!);
|
||||
|
||||
await wait(200);
|
||||
const inputs = [].slice
|
||||
.call(container.querySelectorAll('tbody td input[name="a"]'))
|
||||
.map((td: any) => td.value);
|
||||
|
||||
expect(inputs).toEqual(['a1', '']);
|
||||
});
|
||||
|
@ -1,137 +1,156 @@
|
||||
import {render} from '@testing-library/react';
|
||||
import '../../src';
|
||||
import {render as amisRender} from '../../src';
|
||||
import {makeEnv} from '../helper';
|
||||
import {makeEnv, wait} from '../helper';
|
||||
|
||||
const tag = (label: string) => render(
|
||||
amisRender(
|
||||
{type: 'tag', label},
|
||||
{},
|
||||
makeEnv({})
|
||||
)
|
||||
).container;
|
||||
const tag = (label: string) =>
|
||||
render(amisRender({type: 'tag', label}, {}, makeEnv({}))).container;
|
||||
|
||||
test('Renderer:mapping width object map', async () => {
|
||||
const setup = (value?: any) => render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'mapping',
|
||||
map: {
|
||||
1: "漂亮",
|
||||
2: "开心",
|
||||
3: "惊吓",
|
||||
4: "紧张",
|
||||
'*': '其他',
|
||||
const setup = (value?: any) =>
|
||||
render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'mapping',
|
||||
map: {
|
||||
1: '漂亮',
|
||||
2: '开心',
|
||||
3: '惊吓',
|
||||
4: '紧张',
|
||||
'*': '其他'
|
||||
},
|
||||
...(value !== undefined ? {value} : {})
|
||||
},
|
||||
...(value !== undefined ? {value} : {})
|
||||
},
|
||||
{},
|
||||
makeEnv({})
|
||||
)
|
||||
).container;
|
||||
{},
|
||||
makeEnv({})
|
||||
)
|
||||
).container;
|
||||
|
||||
const noValue = setup().querySelector('.cxd-MappingField .text-muted')! as HTMLElement;
|
||||
const noValue = setup().querySelector(
|
||||
'.cxd-MappingField .text-muted'
|
||||
)! as HTMLElement;
|
||||
expect(noValue.innerHTML).toBe('-');
|
||||
|
||||
const value1 = setup(1).querySelector('.cxd-MappingField .cxd-TplField span')! as HTMLElement;
|
||||
const value1 = setup(1).querySelector(
|
||||
'.cxd-MappingField .cxd-TplField span'
|
||||
)! as HTMLElement;
|
||||
expect(value1.innerHTML).toBe('漂亮');
|
||||
|
||||
const value5 = setup(5).querySelector('.cxd-MappingField .cxd-TplField span')! as HTMLElement;
|
||||
const value5 = setup(5).querySelector(
|
||||
'.cxd-MappingField .cxd-TplField span'
|
||||
)! as HTMLElement;
|
||||
expect(value5.innerHTML).toBe('其他');
|
||||
});
|
||||
|
||||
test('Renderer:mapping width array map', async () => {
|
||||
const setup = (value?: any) => render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'mapping',
|
||||
map: [
|
||||
{1: "漂亮"},
|
||||
{2: "开心"},
|
||||
{3: "惊吓"},
|
||||
{4: "紧张"},
|
||||
{'*': '其他'}
|
||||
],
|
||||
...(value !== undefined ? {value} : {})
|
||||
},
|
||||
{},
|
||||
makeEnv({})
|
||||
)
|
||||
).container;
|
||||
const setup = (value?: any) =>
|
||||
render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'mapping',
|
||||
map: [
|
||||
{1: '漂亮'},
|
||||
{2: '开心'},
|
||||
{3: '惊吓'},
|
||||
{4: '紧张'},
|
||||
{'*': '其他'}
|
||||
],
|
||||
...(value !== undefined ? {value} : {})
|
||||
},
|
||||
{},
|
||||
makeEnv({})
|
||||
)
|
||||
).container;
|
||||
|
||||
const noValue = setup().querySelector('.cxd-MappingField .text-muted')! as HTMLElement;
|
||||
const noValue = setup().querySelector(
|
||||
'.cxd-MappingField .text-muted'
|
||||
)! as HTMLElement;
|
||||
expect(noValue.innerHTML).toBe('-');
|
||||
|
||||
const value1 = setup(1).querySelector('.cxd-MappingField .cxd-TplField span')! as HTMLElement;
|
||||
const value1 = setup(1).querySelector(
|
||||
'.cxd-MappingField .cxd-TplField span'
|
||||
)! as HTMLElement;
|
||||
expect(value1.innerHTML).toBe('漂亮');
|
||||
|
||||
const value5 = setup(5).querySelector('.cxd-MappingField .cxd-TplField span')! as HTMLElement;
|
||||
const value5 = setup(5).querySelector(
|
||||
'.cxd-MappingField .cxd-TplField span'
|
||||
)! as HTMLElement;
|
||||
expect(value5.innerHTML).toBe('其他');
|
||||
});
|
||||
|
||||
test('Renderer:mapping attr: valueField and labelField', async () => {
|
||||
const setup = (value?: any) => render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'mapping',
|
||||
map: [
|
||||
{
|
||||
name: 1,
|
||||
text: '漂亮'
|
||||
},
|
||||
{
|
||||
name: 2,
|
||||
text: '开心'
|
||||
},
|
||||
{
|
||||
name: '*',
|
||||
text: '其他'
|
||||
}
|
||||
],
|
||||
labelField: 'text',
|
||||
valueField: 'name',
|
||||
...(value !== undefined ? {value} : {})
|
||||
},
|
||||
{},
|
||||
makeEnv({})
|
||||
)
|
||||
).container;
|
||||
const setup = (value?: any) =>
|
||||
render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'mapping',
|
||||
map: [
|
||||
{
|
||||
name: 1,
|
||||
text: '漂亮'
|
||||
},
|
||||
{
|
||||
name: 2,
|
||||
text: '开心'
|
||||
},
|
||||
{
|
||||
name: '*',
|
||||
text: '其他'
|
||||
}
|
||||
],
|
||||
labelField: 'text',
|
||||
valueField: 'name',
|
||||
...(value !== undefined ? {value} : {})
|
||||
},
|
||||
{},
|
||||
makeEnv({})
|
||||
)
|
||||
).container;
|
||||
|
||||
const noValue = setup().querySelector('.cxd-MappingField .text-muted')! as HTMLElement;
|
||||
const noValue = setup().querySelector(
|
||||
'.cxd-MappingField .text-muted'
|
||||
)! as HTMLElement;
|
||||
expect(noValue.innerHTML).toBe('-');
|
||||
|
||||
const value1 = setup(1).querySelector('.cxd-MappingField .cxd-TplField span')! as HTMLElement;
|
||||
const value1 = setup(1).querySelector(
|
||||
'.cxd-MappingField .cxd-TplField span'
|
||||
)! as HTMLElement;
|
||||
expect(value1.innerHTML).toBe('漂亮');
|
||||
|
||||
const value5 = setup(5).querySelector('.cxd-MappingField .cxd-TplField span')! as HTMLElement;
|
||||
const value5 = setup(5).querySelector(
|
||||
'.cxd-MappingField .cxd-TplField span'
|
||||
)! as HTMLElement;
|
||||
expect(value5.innerHTML).toBe('其他');
|
||||
});
|
||||
|
||||
test('Renderer:mapping attr: itemSchema when simple map', async () => {
|
||||
const setup = (value?: any) => render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'mapping',
|
||||
map: [
|
||||
{1: "漂亮"},
|
||||
{2: "开心"},
|
||||
{3: "惊吓"},
|
||||
{4: "紧张"},
|
||||
{'*': '其他'}
|
||||
],
|
||||
valueField: 'name',
|
||||
...(value !== undefined ? {value} : {}),
|
||||
itemSchema: {
|
||||
type: 'tag',
|
||||
label: '${item}'
|
||||
}
|
||||
},
|
||||
{},
|
||||
makeEnv({})
|
||||
)
|
||||
).container;
|
||||
const setup = (value?: any) =>
|
||||
render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'mapping',
|
||||
map: [
|
||||
{1: '漂亮'},
|
||||
{2: '开心'},
|
||||
{3: '惊吓'},
|
||||
{4: '紧张'},
|
||||
{'*': '其他'}
|
||||
],
|
||||
valueField: 'name',
|
||||
...(value !== undefined ? {value} : {}),
|
||||
itemSchema: {
|
||||
type: 'tag',
|
||||
label: '${item}'
|
||||
}
|
||||
},
|
||||
{},
|
||||
makeEnv({})
|
||||
)
|
||||
).container;
|
||||
|
||||
const noValue = setup().querySelector('.cxd-MappingField .text-muted')! as HTMLElement;
|
||||
const noValue = setup().querySelector(
|
||||
'.cxd-MappingField .text-muted'
|
||||
)! as HTMLElement;
|
||||
expect(noValue.innerHTML).toBe('-');
|
||||
|
||||
const value1 = setup(1).querySelector('.cxd-MappingField')! as HTMLElement;
|
||||
@ -142,37 +161,40 @@ test('Renderer:mapping attr: itemSchema when simple map', async () => {
|
||||
});
|
||||
|
||||
test('Renderer:mapping attr: itemSchema when normal map', async () => {
|
||||
const setup = (value?: any) => render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'mapping',
|
||||
map: [
|
||||
{
|
||||
name: 1,
|
||||
text: '漂亮'
|
||||
},
|
||||
{
|
||||
name: 2,
|
||||
text: '开心'
|
||||
},
|
||||
{
|
||||
name: '*',
|
||||
text: '其他'
|
||||
const setup = (value?: any) =>
|
||||
render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'mapping',
|
||||
map: [
|
||||
{
|
||||
name: 1,
|
||||
text: '漂亮'
|
||||
},
|
||||
{
|
||||
name: 2,
|
||||
text: '开心'
|
||||
},
|
||||
{
|
||||
name: '*',
|
||||
text: '其他'
|
||||
}
|
||||
],
|
||||
valueField: 'name',
|
||||
...(value !== undefined ? {value} : {}),
|
||||
itemSchema: {
|
||||
type: 'tag',
|
||||
label: '${name} ${text}'
|
||||
}
|
||||
],
|
||||
valueField: 'name',
|
||||
...(value !== undefined ? {value} : {}),
|
||||
itemSchema: {
|
||||
type: 'tag',
|
||||
label: '${name} ${text}'
|
||||
}
|
||||
},
|
||||
{},
|
||||
makeEnv({})
|
||||
)
|
||||
).container;
|
||||
},
|
||||
{},
|
||||
makeEnv({})
|
||||
)
|
||||
).container;
|
||||
|
||||
const noValue = setup().querySelector('.cxd-MappingField .text-muted')! as HTMLElement;
|
||||
const noValue = setup().querySelector(
|
||||
'.cxd-MappingField .text-muted'
|
||||
)! as HTMLElement;
|
||||
expect(noValue.innerHTML).toBe('-');
|
||||
|
||||
const value1 = setup(1).querySelector('.cxd-MappingField')! as HTMLElement;
|
||||
@ -204,23 +226,24 @@ test('Renderer:mapping', async () => {
|
||||
});
|
||||
|
||||
test('Renderer:mapping html', async () => {
|
||||
const setup = (value?: any) => render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'mapping',
|
||||
map: {
|
||||
1: "<span class='label label-info'>漂亮</span>",
|
||||
2: "<span class='label label-success'>开心</span>",
|
||||
3: "<span class='label label-danger'>惊吓</span>",
|
||||
4: "<span class='label label-warning'>紧张</span>",
|
||||
'*': '其他'
|
||||
const setup = (value?: any) =>
|
||||
render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'mapping',
|
||||
map: {
|
||||
1: "<span class='label label-info'>漂亮</span>",
|
||||
2: "<span class='label label-success'>开心</span>",
|
||||
3: "<span class='label label-danger'>惊吓</span>",
|
||||
4: "<span class='label label-warning'>紧张</span>",
|
||||
'*': '其他'
|
||||
},
|
||||
...(value !== undefined ? {value} : {})
|
||||
},
|
||||
...(value !== undefined ? {value} : {})
|
||||
},
|
||||
{},
|
||||
makeEnv({})
|
||||
)
|
||||
).container;
|
||||
{},
|
||||
makeEnv({})
|
||||
)
|
||||
).container;
|
||||
|
||||
expect(setup()).toMatchSnapshot();
|
||||
expect(setup(1)).toMatchSnapshot();
|
||||
@ -228,25 +251,28 @@ test('Renderer:mapping html', async () => {
|
||||
});
|
||||
|
||||
test('Renderer:mapping schema', async () => {
|
||||
const setup = (value?: any) => render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'mapping',
|
||||
map: {
|
||||
1: {type: 'tag', label: '漂亮'},
|
||||
2: {type: 'tag', label: '开心'},
|
||||
3: {type: 'tag', label: '惊吓'},
|
||||
4: {type: 'tag', label: '紧张'},
|
||||
'*': {type: 'tag', label: '其他'}
|
||||
const setup = (value?: any) =>
|
||||
render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'mapping',
|
||||
map: {
|
||||
1: {type: 'tag', label: '漂亮'},
|
||||
2: {type: 'tag', label: '开心'},
|
||||
3: {type: 'tag', label: '惊吓'},
|
||||
4: {type: 'tag', label: '紧张'},
|
||||
'*': {type: 'tag', label: '其他'}
|
||||
},
|
||||
...(value !== undefined ? {value} : {})
|
||||
},
|
||||
...(value !== undefined ? {value} : {})
|
||||
},
|
||||
{},
|
||||
makeEnv({})
|
||||
)
|
||||
).container;
|
||||
{},
|
||||
makeEnv({})
|
||||
)
|
||||
).container;
|
||||
|
||||
const noValue = setup().querySelector('.cxd-MappingField .text-muted')! as HTMLElement;
|
||||
const noValue = setup().querySelector(
|
||||
'.cxd-MappingField .text-muted'
|
||||
)! as HTMLElement;
|
||||
expect(noValue.innerHTML).toBe('-');
|
||||
|
||||
const value1 = setup(1).querySelector('.cxd-MappingField')! as HTMLElement;
|
||||
@ -255,3 +281,68 @@ test('Renderer:mapping schema', async () => {
|
||||
const value5 = setup(5).querySelector('.cxd-MappingField')! as HTMLElement;
|
||||
expect(value5.innerHTML).toBe(tag('其他').innerHTML);
|
||||
});
|
||||
|
||||
// 对应 issue https://github.com/baidu/amis/issues/9613
|
||||
test('Renderer:mapping schema status', async () => {
|
||||
const {container, getByText} = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'page',
|
||||
data: {
|
||||
items: [
|
||||
{
|
||||
status: 1,
|
||||
id: 1
|
||||
}
|
||||
]
|
||||
},
|
||||
body: [
|
||||
{
|
||||
type: 'table',
|
||||
title: '表格',
|
||||
columns: [
|
||||
{
|
||||
name: 'id',
|
||||
label: 'ID'
|
||||
},
|
||||
{
|
||||
name: 'status',
|
||||
label: '状态2',
|
||||
type: 'mapping',
|
||||
map: {
|
||||
'*': {
|
||||
type: 'status',
|
||||
map: {
|
||||
'0': 'schedule',
|
||||
'1': 'rolling',
|
||||
'2': 'success',
|
||||
'3': 'fail',
|
||||
'4': 'warning'
|
||||
},
|
||||
labelMap: {
|
||||
'2': '任务成功',
|
||||
'1': '处理中',
|
||||
'3': '异常终止',
|
||||
'0': '等待中',
|
||||
'4': '已过期'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{},
|
||||
makeEnv({})
|
||||
)
|
||||
);
|
||||
|
||||
await wait(200);
|
||||
|
||||
expect(
|
||||
[].slice
|
||||
.call(container.querySelectorAll('tbody td'))
|
||||
.map((td: any) => td.textContent)
|
||||
).toEqual(['1', '处理中']);
|
||||
});
|
||||
|
@ -585,7 +585,8 @@ test('Renderer:Nav with icons', async () => {
|
||||
|
||||
// 9.Nav在Dialog里
|
||||
test('Renderer:Nav with Dialog', async () => {
|
||||
const {container, getByText} = render(
|
||||
let container: HTMLElement;
|
||||
const renderResult: any = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'page',
|
||||
@ -678,6 +679,8 @@ test('Renderer:Nav with Dialog', async () => {
|
||||
})
|
||||
)
|
||||
);
|
||||
const getByText = renderResult.getByText;
|
||||
container = renderResult.container;
|
||||
expect(container).toMatchSnapshot();
|
||||
|
||||
fireEvent.click(getByText('点击弹框'));
|
||||
|
@ -687,7 +687,8 @@ test('Renderer:Page handleAction actionType=url|link', async () => {
|
||||
});
|
||||
|
||||
test('Renderer:Page handleAction actionType=dialog default', async () => {
|
||||
const {getByText, container}: any = render(
|
||||
let container: HTMLElement;
|
||||
const renderResult: any = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'page',
|
||||
@ -708,6 +709,8 @@ test('Renderer:Page handleAction actionType=dialog default', async () => {
|
||||
})
|
||||
)
|
||||
);
|
||||
const getByText = renderResult.getByText;
|
||||
container = renderResult.container;
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByText('OpenDialog')).toBeInTheDocument();
|
||||
@ -728,7 +731,8 @@ test('Renderer:Page handleAction actionType=dialog default', async () => {
|
||||
});
|
||||
|
||||
test('Renderer:Page handleAction actionType=dialog mergeData', async () => {
|
||||
const {getByText, container}: any = render(
|
||||
let container: HTMLElement;
|
||||
const renderResult: any = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'page',
|
||||
@ -767,6 +771,8 @@ test('Renderer:Page handleAction actionType=dialog mergeData', async () => {
|
||||
})
|
||||
)
|
||||
);
|
||||
const getByText = renderResult.getByText;
|
||||
container = renderResult.container;
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByText('OpenDialog')).toBeInTheDocument();
|
||||
@ -787,7 +793,8 @@ test('Renderer:Page handleAction actionType=dialog mergeData', async () => {
|
||||
});
|
||||
|
||||
test('Renderer:Page handleAction actionType=drawer default', async () => {
|
||||
const {getByText, container}: any = render(
|
||||
let container: HTMLElement;
|
||||
const renderResult: any = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'page',
|
||||
@ -808,6 +815,8 @@ test('Renderer:Page handleAction actionType=drawer default', async () => {
|
||||
})
|
||||
)
|
||||
);
|
||||
const getByText = renderResult.getByText;
|
||||
container = renderResult.container;
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByText('OpenDrawer')).toBeInTheDocument();
|
||||
@ -827,7 +836,8 @@ test('Renderer:Page handleAction actionType=drawer default', async () => {
|
||||
});
|
||||
|
||||
test('Renderer:Page handleAction actionType=drawer mergeData', async () => {
|
||||
const {getByText, container}: any = render(
|
||||
let container: HTMLElement;
|
||||
const renderResult: any = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'page',
|
||||
@ -866,6 +876,8 @@ test('Renderer:Page handleAction actionType=drawer mergeData', async () => {
|
||||
})
|
||||
)
|
||||
);
|
||||
const getByText = renderResult.getByText;
|
||||
container = renderResult.container;
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByText('OpenDrawer')).toBeInTheDocument();
|
||||
@ -898,7 +910,8 @@ test('Renderer:Page handleAction actionType=ajax', async () => {
|
||||
}
|
||||
})
|
||||
);
|
||||
const {getByText, container}: any = render(
|
||||
let container: HTMLElement;
|
||||
const renderResult: any = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'page',
|
||||
@ -919,6 +932,8 @@ test('Renderer:Page handleAction actionType=ajax', async () => {
|
||||
})
|
||||
)
|
||||
);
|
||||
const getByText = renderResult.getByText;
|
||||
container = renderResult.container;
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByText('RequestAjax')).toBeInTheDocument();
|
||||
@ -974,7 +989,8 @@ test('Renderer:Page handleAction actionType=ajax & feedback', async () => {
|
||||
}
|
||||
})
|
||||
);
|
||||
const {getByText, container}: any = render(
|
||||
let container: HTMLElement;
|
||||
const renderResult: any = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'page',
|
||||
@ -998,6 +1014,8 @@ test('Renderer:Page handleAction actionType=ajax & feedback', async () => {
|
||||
})
|
||||
)
|
||||
);
|
||||
const getByText = renderResult.getByText;
|
||||
container = renderResult.container;
|
||||
|
||||
fireEvent.click(getByText(/RequestAjax/));
|
||||
await waitFor(() => {
|
||||
@ -1169,7 +1187,8 @@ test('Renderer:Page initApi reload by Dialog action', async () => {
|
||||
}
|
||||
})
|
||||
);
|
||||
const {container, getByText, rerender}: any = render(
|
||||
let container: HTMLElement;
|
||||
const renderResult: any = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'page',
|
||||
@ -1205,6 +1224,8 @@ test('Renderer:Page initApi reload by Dialog action', async () => {
|
||||
})
|
||||
)
|
||||
);
|
||||
const getByText = renderResult.getByText;
|
||||
container = renderResult.container;
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByText('The variable value is 1')).toBeInTheDocument();
|
||||
@ -1246,7 +1267,8 @@ test('Renderer:Page initApi reload by Drawer action', async () => {
|
||||
}
|
||||
})
|
||||
);
|
||||
const {container, getByText, rerender}: any = render(
|
||||
let container: HTMLElement;
|
||||
const renderResult: any = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'page',
|
||||
@ -1282,6 +1304,8 @@ test('Renderer:Page initApi reload by Drawer action', async () => {
|
||||
})
|
||||
)
|
||||
);
|
||||
const getByText = renderResult.getByText;
|
||||
container = renderResult.container;
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByText('The variable value is 1')).toBeInTheDocument();
|
||||
@ -1323,7 +1347,8 @@ test('Renderer:Page initApi reload by Form submit', async () => {
|
||||
}
|
||||
})
|
||||
);
|
||||
const {container, getByText, rerender}: any = render(
|
||||
let container: HTMLElement;
|
||||
const renderResult: any = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'page',
|
||||
@ -1358,6 +1383,8 @@ test('Renderer:Page initApi reload by Form submit', async () => {
|
||||
})
|
||||
)
|
||||
);
|
||||
const getByText = renderResult.getByText;
|
||||
container = renderResult.container;
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByText(/Submit/)).toBeInTheDocument();
|
||||
|
@ -1125,6 +1125,109 @@ test('Renderer:table-accessSuperData4', () => {
|
||||
expect(td2?.textContent).toBe('-');
|
||||
});
|
||||
|
||||
// https://github.com/baidu/amis/issues/9556
|
||||
test('Renderer:table-accessSuperData5', async () => {
|
||||
const {container, getByText} = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'page',
|
||||
data: {
|
||||
engine: 'xxx',
|
||||
items: [
|
||||
{
|
||||
id: 1
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
engine: 'Trident'
|
||||
}
|
||||
]
|
||||
},
|
||||
body: {
|
||||
type: 'table',
|
||||
name: 'crud',
|
||||
source: '${items}',
|
||||
columns: [
|
||||
{
|
||||
name: 'id',
|
||||
label: 'ID'
|
||||
},
|
||||
{
|
||||
type: 'static-text',
|
||||
name: 'engine',
|
||||
label: 'Rendering engine'
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
name: 'engine',
|
||||
label: 'Rendering engine'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{},
|
||||
makeEnv({})
|
||||
)
|
||||
);
|
||||
|
||||
await wait(200);
|
||||
const tds = [].slice
|
||||
.call(container.querySelectorAll('td'))
|
||||
.map((td: any) => td.textContent);
|
||||
expect(tds).toEqual(['1', '-', '-', '2', 'Trident', 'Trident']);
|
||||
});
|
||||
test('Renderer:table-accessSuperData6', async () => {
|
||||
const {container, getByText} = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'page',
|
||||
data: {
|
||||
engine: 'xxx',
|
||||
items: [
|
||||
{
|
||||
id: 1
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
engine: 'Trident'
|
||||
}
|
||||
]
|
||||
},
|
||||
body: {
|
||||
type: 'table',
|
||||
name: 'crud',
|
||||
source: '${items}',
|
||||
columns: [
|
||||
{
|
||||
name: 'id',
|
||||
label: 'ID'
|
||||
},
|
||||
{
|
||||
type: 'static-text',
|
||||
name: 'engine',
|
||||
label: 'Rendering engine',
|
||||
canAccessSuperData: true
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
name: 'engine',
|
||||
label: 'Rendering engine'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{},
|
||||
makeEnv({})
|
||||
)
|
||||
);
|
||||
|
||||
await wait(200);
|
||||
const tds = [].slice
|
||||
.call(container.querySelectorAll('td'))
|
||||
.map((td: any) => td.textContent);
|
||||
expect(tds).toEqual(['1', 'xxx', '-', '2', 'Trident', 'Trident']);
|
||||
});
|
||||
|
||||
test('Renderer:table-each', () => {
|
||||
const {container, getByText} = render(
|
||||
amisRender(
|
||||
|
@ -1420,7 +1420,8 @@ test('Renderer:Wizard target', async () => {
|
||||
});
|
||||
|
||||
test('Renderer:Wizard dialog', async () => {
|
||||
const {getByText, container}: any = render(
|
||||
let container: HTMLElement;
|
||||
const renderResult: any = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'page',
|
||||
@ -1477,6 +1478,8 @@ test('Renderer:Wizard dialog', async () => {
|
||||
})
|
||||
)
|
||||
);
|
||||
const getByText = renderResult.getByText;
|
||||
container = renderResult.container;
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByText(/OpenDialog/)).toBeInTheDocument();
|
||||
@ -1545,5 +1548,4 @@ test('Renderer:Wizard mode', async () => {
|
||||
expect(steps[0].className).toBe('is-finish');
|
||||
expect(steps[1].className).toBe('is-process');
|
||||
});
|
||||
|
||||
});
|
||||
|
@ -903,7 +903,7 @@ exports[`Renderer:Pagination with showPerPage & perPageAvailable & showPageInput
|
||||
<div
|
||||
class="cxd-PopOver cxd-Select-popover cxd-PopOver--leftBottomLeftTop cxd-PopOver--v-top"
|
||||
role="popover"
|
||||
style="display: block; width: auto; left: 0px; top: 0px; position: relative;"
|
||||
style="display: block; width: auto; left: 1024px; top: 768px; position: relative;"
|
||||
theme="cxd"
|
||||
>
|
||||
<div
|
||||
|
@ -244,4 +244,4 @@
|
||||
"react-dom": ">=16.8.6"
|
||||
},
|
||||
"gitHead": "37d23b4a8eb1c663bc38e8dd9040889ea1526ec4"
|
||||
}
|
||||
}
|
@ -8,7 +8,13 @@ import {
|
||||
SpinnerExtraProps
|
||||
} from 'amis-ui';
|
||||
import {Layout} from 'amis-ui';
|
||||
import {Renderer, RendererProps, filter, replaceText} from 'amis-core';
|
||||
import {
|
||||
Renderer,
|
||||
RendererProps,
|
||||
envOverwrite,
|
||||
filter,
|
||||
replaceText
|
||||
} from 'amis-core';
|
||||
import {
|
||||
BaseSchema,
|
||||
SchemaApi,
|
||||
@ -244,11 +250,13 @@ export default class App extends React.Component<AppProps, object> {
|
||||
store,
|
||||
env,
|
||||
showFullBreadcrumbPath = false,
|
||||
showBreadcrumbHomePath = true
|
||||
showBreadcrumbHomePath = true,
|
||||
locale
|
||||
} = this.props;
|
||||
|
||||
if (isEffectiveApi(api, store.data)) {
|
||||
const json = await store.fetchInitData(api, store.data, {});
|
||||
|
||||
if (env.replaceText) {
|
||||
json.data = replaceText(
|
||||
json.data,
|
||||
@ -258,6 +266,8 @@ export default class App extends React.Component<AppProps, object> {
|
||||
}
|
||||
|
||||
if (json?.data.pages) {
|
||||
json.data = envOverwrite(json.data, locale);
|
||||
|
||||
store.setPages(json.data.pages);
|
||||
store.updateActivePage(
|
||||
Object.assign({}, env ?? {}, {
|
||||
|
@ -7,7 +7,8 @@ import {
|
||||
RendererProps,
|
||||
evalExpressionWithConditionBuilder,
|
||||
filterTarget,
|
||||
mapTree
|
||||
mapTree,
|
||||
buildTestId
|
||||
} from 'amis-core';
|
||||
import {SchemaNode, Schema, ActionObject, PlainObject} from 'amis-core';
|
||||
import {CRUDStore, ICRUDStore} from 'amis-core';
|
||||
@ -760,6 +761,11 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
stopAutoRefreshWhenModalIsOpen
|
||||
} = this.props;
|
||||
|
||||
if (store.loading) {
|
||||
//由于curd的loading样式未遮罩按钮部分,如果处于加载中时不处理操作
|
||||
return;
|
||||
}
|
||||
|
||||
if (action.actionType === 'dialog') {
|
||||
store.setCurrentAction(action);
|
||||
const idx: number = (ctx as any).index;
|
||||
@ -2511,6 +2517,7 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
onSearchableFromInit,
|
||||
headerToolbarRender,
|
||||
footerToolbarRender,
|
||||
testid,
|
||||
...rest
|
||||
} = this.props;
|
||||
|
||||
@ -2521,6 +2528,7 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
'is-mobile': isMobile()
|
||||
})}
|
||||
style={style}
|
||||
{...buildTestId(testid)}
|
||||
>
|
||||
{filter && (!store.filterTogggable || store.filterVisible)
|
||||
? render(
|
||||
|
@ -30,7 +30,8 @@ import {
|
||||
isApiOutdated,
|
||||
isPureVariable,
|
||||
resolveVariableAndFilter,
|
||||
parsePrimitiveQueryString
|
||||
parsePrimitiveQueryString,
|
||||
buildTestId
|
||||
} from 'amis-core';
|
||||
import {Html, SpinnerExtraProps} from 'amis-ui';
|
||||
import {
|
||||
@ -1308,6 +1309,7 @@ export default class CRUD2 extends React.Component<CRUD2Props, any> {
|
||||
columnsTogglable,
|
||||
headerToolbarClassName,
|
||||
footerToolbarClassName,
|
||||
testid,
|
||||
...rest
|
||||
} = this.props;
|
||||
|
||||
@ -1317,6 +1319,7 @@ export default class CRUD2 extends React.Component<CRUD2Props, any> {
|
||||
'is-loading': store.loading
|
||||
})}
|
||||
style={style}
|
||||
{...buildTestId(testid)}
|
||||
>
|
||||
<div className={cx('Crud2-filter')}>
|
||||
{this.renderFilter(filterSchema)}
|
||||
|
@ -8,7 +8,8 @@ import {
|
||||
isPureVariable,
|
||||
resolveVariableAndFilter,
|
||||
CustomStyle,
|
||||
setThemeClassName
|
||||
setThemeClassName,
|
||||
buildTestId
|
||||
} from 'amis-core';
|
||||
import {DndContainer as DndWrapper} from 'amis-ui';
|
||||
import {BaseSchema, SchemaClassName, SchemaCollection} from '../Schema';
|
||||
@ -195,7 +196,8 @@ export default class Container<T> extends React.Component<
|
||||
wrapperCustomStyle,
|
||||
env,
|
||||
themeCss,
|
||||
baseControlClassName
|
||||
baseControlClassName,
|
||||
testid
|
||||
} = this.props;
|
||||
const finalDraggable: boolean = isPureVariable(draggable)
|
||||
? resolveVariableAndFilter(draggable, data, '| raw')
|
||||
@ -231,6 +233,7 @@ export default class Container<T> extends React.Component<
|
||||
onMouseEnter={this.handleMouseEnter}
|
||||
onMouseLeave={this.handleMouseLeave}
|
||||
style={buildStyle(style, data)}
|
||||
{...buildTestId(testid)}
|
||||
>
|
||||
{this.renderBody()}
|
||||
<CustomStyle
|
||||
|
@ -8,7 +8,8 @@ import {
|
||||
Renderer,
|
||||
RendererProps,
|
||||
CustomStyle,
|
||||
setThemeClassName
|
||||
setThemeClassName,
|
||||
buildTestId
|
||||
} from 'amis-core';
|
||||
import {Schema} from 'amis-core';
|
||||
import {BaseSchema, SchemaCollection, SchemaObject} from '../Schema';
|
||||
@ -111,7 +112,8 @@ export default class Flex extends React.Component<FlexProps, object> {
|
||||
wrapperCustomStyle,
|
||||
env,
|
||||
themeCss,
|
||||
classnames: cx
|
||||
classnames: cx,
|
||||
testid
|
||||
} = this.props;
|
||||
const styleVar = buildStyle(style, data);
|
||||
const flexStyle = {
|
||||
@ -150,6 +152,7 @@ export default class Flex extends React.Component<FlexProps, object> {
|
||||
themeCss: wrapperCustomStyle
|
||||
})
|
||||
)}
|
||||
{...buildTestId(testid)}
|
||||
>
|
||||
{(Array.isArray(items) ? items : items ? [items] : []).map(
|
||||
(item, key) =>
|
||||
|
@ -73,6 +73,7 @@ function normalizeValue(value: any, language?: string) {
|
||||
export class DiffEditor extends React.Component<DiffEditorProps, any> {
|
||||
static defaultProps: Partial<DiffEditorProps> = {
|
||||
language: 'javascript',
|
||||
editorTheme: 'vs',
|
||||
options: {
|
||||
automaticLayout: false,
|
||||
selectOnLineNumbers: true,
|
||||
@ -303,7 +304,7 @@ export class DiffEditor extends React.Component<DiffEditorProps, any> {
|
||||
size,
|
||||
options,
|
||||
language,
|
||||
theme,
|
||||
editorTheme,
|
||||
classnames: cx
|
||||
} = this.props;
|
||||
|
||||
@ -325,7 +326,7 @@ export class DiffEditor extends React.Component<DiffEditorProps, any> {
|
||||
onChange={onChange}
|
||||
disabled={disabled}
|
||||
language={language}
|
||||
theme={theme}
|
||||
editorTheme={editorTheme}
|
||||
editorDidMount={this.handleEditorMounted}
|
||||
editorFactory={this.editorFactory}
|
||||
options={{
|
||||
|
@ -121,7 +121,7 @@ export class BaseTabsTransferRenderer<
|
||||
}
|
||||
} else if (term) {
|
||||
return filterTree(
|
||||
options,
|
||||
option.children || options,
|
||||
(option: Option, key: number, level: number, paths: Array<Option>) => {
|
||||
return !!(
|
||||
(Array.isArray(option.children) && option.children.length) ||
|
||||
@ -307,7 +307,8 @@ export class TabsTransferRenderer extends BaseTabsTransferRenderer<TabsTransferP
|
||||
valueTpl,
|
||||
menuTpl,
|
||||
data,
|
||||
mobileUI
|
||||
mobileUI,
|
||||
initiallyOpen = true
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
@ -341,6 +342,7 @@ export class TabsTransferRenderer extends BaseTabsTransferRenderer<TabsTransferP
|
||||
valueField={valueField}
|
||||
ctx={data}
|
||||
mobileUI={mobileUI}
|
||||
initiallyOpen={initiallyOpen}
|
||||
/>
|
||||
|
||||
<Spinner
|
||||
|
@ -112,7 +112,9 @@ export class TabsTransferPickerRenderer extends BaseTabsTransferRenderer<TabsTra
|
||||
mobileUI,
|
||||
env,
|
||||
maxTagCount,
|
||||
overflowTagPopover
|
||||
overflowTagPopover,
|
||||
placeholder,
|
||||
initiallyOpen = true
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
@ -120,6 +122,7 @@ export class TabsTransferPickerRenderer extends BaseTabsTransferRenderer<TabsTra
|
||||
<TabsTransferPicker
|
||||
activeKey={this.state.activeKey}
|
||||
onTabChange={this.onTabChange}
|
||||
placeholder={placeholder}
|
||||
value={selectedOptions}
|
||||
disabled={disabled}
|
||||
options={options}
|
||||
@ -150,6 +153,7 @@ export class TabsTransferPickerRenderer extends BaseTabsTransferRenderer<TabsTra
|
||||
popOverContainer={env?.getModalContainer}
|
||||
maxTagCount={maxTagCount}
|
||||
overflowTagPopover={overflowTagPopover}
|
||||
initiallyOpen={initiallyOpen}
|
||||
/>
|
||||
|
||||
<Spinner
|
||||
|
@ -24,7 +24,8 @@ import {
|
||||
optionValueCompare,
|
||||
resolveVariable,
|
||||
ActionObject,
|
||||
toNumber
|
||||
toNumber,
|
||||
evalExpression
|
||||
} from 'amis-core';
|
||||
import {SpinnerExtraProps, Transfer, Spinner, ResultList} from 'amis-ui';
|
||||
import {
|
||||
@ -169,6 +170,15 @@ export interface TransferControlSchema
|
||||
*/
|
||||
onlyChildren?: boolean;
|
||||
|
||||
/**
|
||||
* 是否默认都展开
|
||||
*/
|
||||
initiallyOpen?: boolean;
|
||||
/**
|
||||
* ui级联关系,true代表级联选中,false代表不级联,默认为true
|
||||
*/
|
||||
autoCheckChildren?: boolean;
|
||||
|
||||
/**
|
||||
* 分页配置,selectMode为默认和table才会生效
|
||||
* @since 3.6.0
|
||||
@ -352,7 +362,11 @@ export class BaseTransferRenderer<
|
||||
}
|
||||
|
||||
@autobind
|
||||
async handleSearch(term: string, cancelExecutor: Function) {
|
||||
async handleSearch(
|
||||
term: string,
|
||||
cancelExecutor: Function,
|
||||
targetPage?: {page: number; perPage?: number}
|
||||
) {
|
||||
const {
|
||||
searchApi,
|
||||
options,
|
||||
@ -368,7 +382,7 @@ export class BaseTransferRenderer<
|
||||
try {
|
||||
const payload = await env.fetcher(
|
||||
searchApi,
|
||||
createObject(data, {term}),
|
||||
createObject(data, {term, ...(targetPage ? targetPage : {})}),
|
||||
{
|
||||
cancelExecutor
|
||||
}
|
||||
@ -384,29 +398,46 @@ export class BaseTransferRenderer<
|
||||
throw new Error(__('CRUD.invalidArray'));
|
||||
}
|
||||
|
||||
return mapTree(result, item => {
|
||||
let resolved: any = null;
|
||||
const value = item[valueField || 'value'];
|
||||
let currentPage = {};
|
||||
if (targetPage) {
|
||||
currentPage = {
|
||||
page: payload.data.page,
|
||||
perPage: targetPage.perPage,
|
||||
total: payload.data.count
|
||||
};
|
||||
}
|
||||
return {
|
||||
items: mapTree(result, item => {
|
||||
let resolved: any = null;
|
||||
const value = item[valueField || 'value'];
|
||||
|
||||
// 只有 value 值有意义的时候,再去找;否则直接返回
|
||||
if (Array.isArray(options) && value !== null && value !== undefined) {
|
||||
resolved = find(options, optionValueCompare(value, valueField));
|
||||
if (item?.children) {
|
||||
resolved = {
|
||||
...resolved,
|
||||
children: item.children
|
||||
};
|
||||
// 只有 value 值有意义的时候,再去找;否则直接返回
|
||||
if (
|
||||
Array.isArray(options) &&
|
||||
value !== null &&
|
||||
value !== undefined
|
||||
) {
|
||||
resolved = find(options, optionValueCompare(value, valueField));
|
||||
if (item?.children) {
|
||||
resolved = {
|
||||
...resolved,
|
||||
children: item.children
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return resolved || item;
|
||||
});
|
||||
return resolved || item;
|
||||
}),
|
||||
...currentPage
|
||||
};
|
||||
} catch (e) {
|
||||
if (!env.isCancel(e) && !searchApi.silent) {
|
||||
env.notify('error', e.message);
|
||||
}
|
||||
|
||||
return [];
|
||||
return {
|
||||
items: []
|
||||
};
|
||||
}
|
||||
} else if (term) {
|
||||
const labelKey = (labelField as string) || 'label';
|
||||
@ -416,29 +447,36 @@ export class BaseTransferRenderer<
|
||||
if (filterOption) {
|
||||
const customFilterOption = getCustomFilterOption(filterOption);
|
||||
if (customFilterOption) {
|
||||
return customFilterOption(options, term, option);
|
||||
return {items: customFilterOption(options, term, option)};
|
||||
} else {
|
||||
env.notify('error', '自定义检索函数不符合要求');
|
||||
return [];
|
||||
return {items: []};
|
||||
}
|
||||
}
|
||||
|
||||
return filterTree(
|
||||
options,
|
||||
(option: Option, key: number, level: number, paths: Array<Option>) => {
|
||||
return !!(
|
||||
(Array.isArray(option.children) && option.children.length) ||
|
||||
!!matchSorter([option].concat(paths), term, {
|
||||
keys: [labelField || 'label', valueField || 'value'],
|
||||
threshold: matchSorter.rankings.CONTAINS
|
||||
}).length
|
||||
);
|
||||
},
|
||||
0,
|
||||
true
|
||||
);
|
||||
return {
|
||||
items: filterTree(
|
||||
options,
|
||||
(
|
||||
option: Option,
|
||||
key: number,
|
||||
level: number,
|
||||
paths: Array<Option>
|
||||
) => {
|
||||
return !!(
|
||||
(Array.isArray(option.children) && option.children.length) ||
|
||||
!!matchSorter([option].concat(paths), term, {
|
||||
keys: [labelField || 'label', valueField || 'value'],
|
||||
threshold: matchSorter.rankings.CONTAINS
|
||||
}).length
|
||||
);
|
||||
},
|
||||
0,
|
||||
true
|
||||
)
|
||||
};
|
||||
} else {
|
||||
return options;
|
||||
return {items: options};
|
||||
}
|
||||
}
|
||||
|
||||
@ -596,7 +634,10 @@ export class BaseTransferRenderer<
|
||||
pagination,
|
||||
formItem,
|
||||
env,
|
||||
popOverContainer
|
||||
popOverContainer,
|
||||
data,
|
||||
autoCheckChildren = true,
|
||||
initiallyOpen = true
|
||||
} = this.props;
|
||||
|
||||
// 目前 LeftOptions 没有接口可以动态加载
|
||||
@ -668,7 +709,11 @@ export class BaseTransferRenderer<
|
||||
'popOverContainerSelector'
|
||||
]),
|
||||
enable:
|
||||
!!formItem?.enableSourcePagination &&
|
||||
(pagination && pagination.enable !== undefined
|
||||
? !!(typeof pagination.enable === 'string'
|
||||
? evalExpression(pagination.enable, data)
|
||||
: pagination.enable)
|
||||
: !!formItem?.enableSourcePagination) &&
|
||||
(!selectMode ||
|
||||
selectMode === 'list' ||
|
||||
selectMode === 'table') &&
|
||||
@ -682,8 +727,9 @@ export class BaseTransferRenderer<
|
||||
popOverContainer: popOverContainer ?? env?.getModalContainer
|
||||
}}
|
||||
onPageChange={this.handlePageChange}
|
||||
initiallyOpen={initiallyOpen}
|
||||
autoCheckChildren={autoCheckChildren}
|
||||
/>
|
||||
|
||||
<Spinner
|
||||
overlay
|
||||
key="info"
|
||||
|
@ -1,4 +1,9 @@
|
||||
import {OptionsControlProps, OptionsControl, resolveEventData} from 'amis-core';
|
||||
import {
|
||||
OptionsControlProps,
|
||||
OptionsControl,
|
||||
resolveEventData,
|
||||
evalExpression
|
||||
} from 'amis-core';
|
||||
import React from 'react';
|
||||
import {Spinner, SpinnerExtraProps} from 'amis-ui';
|
||||
import {BaseTransferRenderer, TransferControlSchema} from './Transfer';
|
||||
@ -7,6 +12,7 @@ import {autobind, createObject} from 'amis-core';
|
||||
import {ActionObject, toNumber} from 'amis-core';
|
||||
import {supportStatic} from './StaticHoc';
|
||||
import {isMobile} from 'amis-core';
|
||||
import pick from 'lodash/pick';
|
||||
|
||||
/**
|
||||
* TransferPicker 穿梭器的弹框形态
|
||||
@ -93,7 +99,14 @@ export class TransferPickerRenderer extends BaseTransferRenderer<TabsTransferPro
|
||||
mobileUI,
|
||||
env,
|
||||
maxTagCount,
|
||||
overflowTagPopover
|
||||
overflowTagPopover,
|
||||
pagination,
|
||||
formItem,
|
||||
data,
|
||||
popOverContainer,
|
||||
placeholder,
|
||||
autoCheckChildren = true,
|
||||
initiallyOpen = true
|
||||
} = this.props;
|
||||
|
||||
// 目前 LeftOptions 没有接口可以动态加载
|
||||
@ -115,6 +128,7 @@ export class TransferPickerRenderer extends BaseTransferRenderer<TabsTransferPro
|
||||
return (
|
||||
<div className={cx('TransferControl', className)}>
|
||||
<TransferPicker
|
||||
placeholder={placeholder}
|
||||
borderMode={borderMode}
|
||||
selectMode={selectMode}
|
||||
value={selectedOptions}
|
||||
@ -148,6 +162,34 @@ export class TransferPickerRenderer extends BaseTransferRenderer<TabsTransferPro
|
||||
popOverContainer={env?.getModalContainer}
|
||||
maxTagCount={maxTagCount}
|
||||
overflowTagPopover={overflowTagPopover}
|
||||
pagination={{
|
||||
...pick(pagination, [
|
||||
'layout',
|
||||
'perPageAvailable',
|
||||
'popOverContainerSelector'
|
||||
]),
|
||||
className: pagination?.className as any,
|
||||
enable:
|
||||
(pagination && pagination.enable !== undefined
|
||||
? !!(typeof pagination.enable === 'string'
|
||||
? evalExpression(pagination.enable, data)
|
||||
: pagination.enable)
|
||||
: !!formItem?.enableSourcePagination) &&
|
||||
(!selectMode ||
|
||||
selectMode === 'list' ||
|
||||
selectMode === 'table') &&
|
||||
options.length > 0,
|
||||
maxButtons: Number.isInteger(pagination?.maxButtons)
|
||||
? pagination?.maxButtons
|
||||
: 5,
|
||||
page: formItem?.sourcePageNum,
|
||||
perPage: formItem?.sourcePerPageNum,
|
||||
total: formItem?.sourceTotalNum,
|
||||
popOverContainer: popOverContainer ?? env?.getModalContainer
|
||||
}}
|
||||
onPageChange={this.handlePageChange}
|
||||
autoCheckChildren={autoCheckChildren}
|
||||
initiallyOpen={initiallyOpen}
|
||||
/>
|
||||
|
||||
<Spinner
|
||||
|
@ -5,7 +5,8 @@ import {
|
||||
RendererProps,
|
||||
buildStyle,
|
||||
CustomStyle,
|
||||
setThemeClassName
|
||||
setThemeClassName,
|
||||
buildTestId
|
||||
} from 'amis-core';
|
||||
import pick from 'lodash/pick';
|
||||
import {BaseSchema, SchemaClassName, SchemaCollection} from '../Schema';
|
||||
@ -212,7 +213,8 @@ export default class Grid<T> extends React.Component<GridProps & T, object> {
|
||||
id,
|
||||
wrapperCustomStyle,
|
||||
env,
|
||||
themeCss
|
||||
themeCss,
|
||||
testid
|
||||
} = this.props;
|
||||
const styleVar = buildStyle(style, data);
|
||||
return (
|
||||
@ -239,6 +241,7 @@ export default class Grid<T> extends React.Component<GridProps & T, object> {
|
||||
})
|
||||
)}
|
||||
style={styleVar}
|
||||
{...buildTestId(testid)}
|
||||
>
|
||||
{this.renderColumns(this.props.columns)}
|
||||
<Spinner loadingConfig={loadingConfig} overlay show={loading} />
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import {Renderer, RendererProps} from 'amis-core';
|
||||
import {buildTestId, Renderer, RendererProps} from 'amis-core';
|
||||
import {Api, SchemaNode, Schema, ActionObject} from 'amis-core';
|
||||
import {isVisible} from 'amis-core';
|
||||
import {BaseSchema, SchemaObject} from '../Schema';
|
||||
@ -172,7 +172,8 @@ export default class Grid2D extends React.Component<Grid2DProps, object> {
|
||||
}
|
||||
|
||||
render() {
|
||||
const {grids, cols, gap, gapRow, width, rowHeight, style} = this.props;
|
||||
const {grids, cols, gap, gapRow, width, rowHeight, style, testid} =
|
||||
this.props;
|
||||
|
||||
const templateColumns = new Array(cols);
|
||||
templateColumns.fill('1fr');
|
||||
@ -214,7 +215,11 @@ export default class Grid2D extends React.Component<Grid2DProps, object> {
|
||||
gridTemplateRows: templateRows.join(' ')
|
||||
};
|
||||
|
||||
return <div style={curStyle}>{this.renderGrids()}</div>;
|
||||
return (
|
||||
<div style={curStyle} {...buildTestId(testid)}>
|
||||
{this.renderGrids()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -253,7 +253,7 @@ export const MappingField = withStore(props =>
|
||||
}
|
||||
|
||||
renderViewValue(value: any) {
|
||||
const {render, itemSchema, data, labelField} = this.props;
|
||||
const {render, itemSchema, data, labelField, name} = this.props;
|
||||
|
||||
if (!itemSchema) {
|
||||
let label = value;
|
||||
@ -265,6 +265,12 @@ export const MappingField = withStore(props =>
|
||||
// object 也没有 type,不能作为schema渲染
|
||||
// 默认取 label 字段
|
||||
label = value['label'];
|
||||
} else {
|
||||
// 不会下发 value 了,所以要把 name 下发一下
|
||||
label = {
|
||||
name,
|
||||
...label
|
||||
};
|
||||
}
|
||||
} else {
|
||||
label = value[labelField || 'label'];
|
||||
|
@ -140,6 +140,7 @@ export const HocQuickEdit =
|
||||
this.handleInit = this.handleInit.bind(this);
|
||||
this.handleChange = this.handleChange.bind(this);
|
||||
this.handleFormItemChange = this.handleFormItemChange.bind(this);
|
||||
this.handleBulkChange = this.handleBulkChange.bind(this);
|
||||
|
||||
this.state = {
|
||||
isOpened: false
|
||||
@ -379,6 +380,18 @@ export const HocQuickEdit =
|
||||
);
|
||||
}
|
||||
|
||||
// autoFill 是通过 onBulkChange 触发的
|
||||
// quickEdit 需要拦截这个,否则修改的数据就是错的
|
||||
handleBulkChange(values: any) {
|
||||
const {onQuickChange, quickEdit} = this.props;
|
||||
onQuickChange(
|
||||
values,
|
||||
(quickEdit as QuickEditConfig).saveImmediately,
|
||||
false,
|
||||
quickEdit as QuickEditConfig
|
||||
);
|
||||
}
|
||||
|
||||
openQuickEdit() {
|
||||
currentOpened = this;
|
||||
this.setState({
|
||||
@ -595,6 +608,7 @@ export const HocQuickEdit =
|
||||
mode: 'normal',
|
||||
value: getPropValue(this.props) ?? '',
|
||||
onChange: this.handleFormItemChange,
|
||||
onBulkChange: this.handleBulkChange,
|
||||
ref: this.formItemRef,
|
||||
defaultStatic: false
|
||||
});
|
||||
@ -608,6 +622,7 @@ export const HocQuickEdit =
|
||||
simpleMode: true,
|
||||
onInit: this.handleInit,
|
||||
onChange: this.handleChange,
|
||||
onBulkChange: this.handleBulkChange,
|
||||
formLazyChange: false,
|
||||
canAccessSuperData,
|
||||
disabled,
|
||||
|
@ -191,7 +191,8 @@ export function AutoFilterForm({
|
||||
autoGenerateFilter,
|
||||
activedSearchableColumns,
|
||||
searchableColumns,
|
||||
searchFormExpanded
|
||||
searchFormExpanded,
|
||||
__ // 保证语言更新后能重新渲染
|
||||
]);
|
||||
|
||||
return render('searchable-form', schema, {
|
||||
|
@ -1,5 +1,10 @@
|
||||
import React from 'react';
|
||||
import {chromeVersion, type IColumn, type ITableStore} from 'amis-core';
|
||||
import {
|
||||
chromeVersion,
|
||||
isSafari,
|
||||
type IColumn,
|
||||
type ITableStore
|
||||
} from 'amis-core';
|
||||
import {observer} from 'mobx-react';
|
||||
|
||||
export function ColGroup({
|
||||
@ -37,7 +42,9 @@ export function ColGroup({
|
||||
// 低版本同时设置 thead>th
|
||||
// The problem is min-width CSS property.
|
||||
// Before Chrome 91, min-width was ignored on COL elements. 91 no longer ignores it.
|
||||
if (typeof chromeVersion === 'number' && chromeVersion < 91) {
|
||||
//
|
||||
// 同时 safari 也存在类似问题,设置 colgroup>col 的 width 属性无效
|
||||
if (isSafari || (typeof chromeVersion === 'number' && chromeVersion < 91)) {
|
||||
React.useEffect(() => {
|
||||
if (domRef.current) {
|
||||
const ths = [].slice.call(
|
||||
|
@ -41,7 +41,8 @@ import {
|
||||
resizeSensor,
|
||||
offset,
|
||||
getStyleNumber,
|
||||
getPropValue
|
||||
getPropValue,
|
||||
buildTestId
|
||||
} from 'amis-core';
|
||||
import {
|
||||
Button,
|
||||
@ -1301,8 +1302,8 @@ export default class Table extends React.Component<TableProps, object> {
|
||||
if (this.resizeLine) {
|
||||
return;
|
||||
}
|
||||
this.props.store.syncTableWidth();
|
||||
this.props.store.initTableWidth();
|
||||
this.props.store.syncTableWidth();
|
||||
this.handleOutterScroll();
|
||||
callback && setTimeout(callback, 20);
|
||||
}
|
||||
@ -1662,6 +1663,7 @@ export default class Table extends React.Component<TableProps, object> {
|
||||
const {store} = this.props;
|
||||
|
||||
store.updateColumns(columns);
|
||||
store.persistSaveToggledColumns();
|
||||
}
|
||||
|
||||
renderAutoFilterForm(): React.ReactNode {
|
||||
@ -2802,7 +2804,8 @@ export default class Table extends React.Component<TableProps, object> {
|
||||
affixHeader,
|
||||
autoFillHeight,
|
||||
autoGenerateFilter,
|
||||
mobileUI
|
||||
mobileUI,
|
||||
testid
|
||||
} = this.props;
|
||||
|
||||
this.renderedToolbars = []; // 用来记录哪些 toolbar 已经渲染了,已经渲染了就不重复渲染了。
|
||||
@ -2821,6 +2824,7 @@ export default class Table extends React.Component<TableProps, object> {
|
||||
'Table--autoFillHeight': autoFillHeight
|
||||
})}
|
||||
style={store.buildStyles(style)}
|
||||
{...buildTestId(testid)}
|
||||
>
|
||||
{autoGenerateFilter ? this.renderAutoFilterForm() : null}
|
||||
{this.renderAffixHeader(tableClassName)}
|
||||
|
@ -8,7 +8,8 @@ import {
|
||||
RendererProps,
|
||||
resolveMappingObject,
|
||||
CustomStyle,
|
||||
setThemeClassName
|
||||
setThemeClassName,
|
||||
buildTestId
|
||||
} from 'amis-core';
|
||||
import {BaseSchema, SchemaObject} from '../Schema';
|
||||
|
||||
@ -276,6 +277,7 @@ export default class TableView extends React.Component<TableViewProps, object> {
|
||||
wrapperCustomStyle,
|
||||
env,
|
||||
themeCss,
|
||||
testid,
|
||||
baseControlClassName
|
||||
} = this.props;
|
||||
|
||||
@ -298,6 +300,7 @@ export default class TableView extends React.Component<TableViewProps, object> {
|
||||
})
|
||||
)}
|
||||
style={{width: width, borderCollapse: 'collapse'}}
|
||||
{...buildTestId(testid)}
|
||||
>
|
||||
{this.renderCaption()}
|
||||
{this.renderCols()}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import {Renderer, RendererProps} from 'amis-core';
|
||||
import {buildTestId, Renderer, RendererProps} from 'amis-core';
|
||||
import {BaseSchema, SchemaCollection} from '../Schema';
|
||||
import {resolveVariable} from 'amis-core';
|
||||
import {SchemaNode} from 'amis-core';
|
||||
@ -59,7 +59,15 @@ export default class Wrapper extends React.Component<WrapperProps, object> {
|
||||
}
|
||||
|
||||
render() {
|
||||
const {className, size, classnames: cx, style, data, wrap} = this.props;
|
||||
const {
|
||||
className,
|
||||
size,
|
||||
classnames: cx,
|
||||
style,
|
||||
data,
|
||||
wrap,
|
||||
testid
|
||||
} = this.props;
|
||||
|
||||
// 期望不要使用,给 form controls 用法自动转换时使用的。
|
||||
if (wrap === false) {
|
||||
@ -74,6 +82,7 @@ export default class Wrapper extends React.Component<WrapperProps, object> {
|
||||
className
|
||||
)}
|
||||
style={buildStyle(style, data)}
|
||||
{...buildTestId(testid)}
|
||||
>
|
||||
{this.renderBody()}
|
||||
</div>
|
||||
|
4
scripts/bot/.gitignore
vendored
4
scripts/bot/.gitignore
vendored
@ -1,7 +1,7 @@
|
||||
db
|
||||
__pycache__
|
||||
text.pickle
|
||||
embedding.pickle
|
||||
text.json
|
||||
embedding.json
|
||||
.env
|
||||
m3e-base
|
||||
flagged
|
||||
|
@ -2,7 +2,7 @@ import sys
|
||||
import os
|
||||
import glob
|
||||
import uuid
|
||||
import pickle
|
||||
import json
|
||||
from embedding import get_embedding
|
||||
from split_markdown import split_markdown
|
||||
from vector_store import get_client
|
||||
@ -21,11 +21,11 @@ text_blocks_by_id = {}
|
||||
embedding_cache = {}
|
||||
|
||||
embedding_cache_file = os.path.join(
|
||||
os.path.dirname(__file__), 'embedding.pickle')
|
||||
os.path.dirname(__file__), 'embedding.json')
|
||||
|
||||
if os.path.exists(embedding_cache_file):
|
||||
with open(embedding_cache_file, 'rb') as f:
|
||||
embedding_cache = pickle.load(f)
|
||||
embedding_cache = json.load(f)
|
||||
|
||||
|
||||
def get_embedding_with_cache(text):
|
||||
@ -65,8 +65,8 @@ for filename in glob.iglob(doc_dir + '**/*.md', recursive=True):
|
||||
)
|
||||
|
||||
|
||||
with open(os.path.join(os.path.dirname(__file__), 'text.pickle'), 'wb') as f:
|
||||
pickle.dump(text_blocks_by_id, f, pickle.HIGHEST_PROTOCOL)
|
||||
with open(os.path.join(os.path.dirname(__file__), 'text.json'), 'w') as f:
|
||||
json.dump(text_blocks_by_id, f)
|
||||
|
||||
with open(embedding_cache_file, 'wb') as f:
|
||||
pickle.dump(embedding_cache, f, pickle.HIGHEST_PROTOCOL)
|
||||
with open(embedding_cache_file, 'w') as f:
|
||||
json.dump(embedding_cache, f)
|
||||
|
@ -3,7 +3,7 @@ from split_markdown import split_markdown
|
||||
from embedding import get_embedding
|
||||
import gradio as gr
|
||||
import os
|
||||
import pickle
|
||||
import json
|
||||
from llm.wenxin import Wenxin, ModelName
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv()
|
||||
@ -15,8 +15,8 @@ collection = chroma_client.get_collection(name="amis")
|
||||
wenxin = Wenxin()
|
||||
|
||||
text_blocks_by_id = {}
|
||||
with open(os.path.join(os.path.dirname(__file__), 'text.pickle'), 'rb') as f:
|
||||
text_blocks_by_id = pickle.load(f)
|
||||
with open(os.path.join(os.path.dirname(__file__), 'text.json'), 'rb') as f:
|
||||
text_blocks_by_id = json.load(f)
|
||||
|
||||
|
||||
def get_prompt(context, query):
|
||||
|
Loading…
Reference in New Issue
Block a user