feat: 数据源面板

This commit is contained in:
muyun.my 2020-09-21 08:33:46 +08:00
parent 56eaff52c8
commit 47f55cafce
15 changed files with 424 additions and 155 deletions

View File

@ -13,7 +13,72 @@
"list": [ "list": [
{ {
"type": "http", "type": "http",
"id": "http1", "id": "请求商家数据,是一个 HTTP 请求,是一个 HTTP 请求,是一个 HTTP 请求",
"isInit": true,
"options": {
"uri": "https://www.taobao.com",
"params": {
"a": 1,
"b": true,
"c": "3"
}
}
},
{
"type": "http",
"id": "请求商家数据2是一个 HTTP 请求,是一个 HTTP 请求,是一个 HTTP 请求",
"isInit": true,
"options": {
"uri": "https://www.taobao.com",
"params": {
"a": 1,
"b": true,
"c": "3"
}
}
},
{
"type": "http",
"id": "请求商家数据3是一个 HTTP 请求,是一个 HTTP 请求,是一个 HTTP 请求",
"isInit": true,
"options": {
"uri": "https://www.taobao.com",
"params": {
"a": 1,
"b": true,
"c": "3"
}
}
},
{
"type": "http",
"id": "请求商家数据4是一个 HTTP 请求,是一个 HTTP 请求,是一个 HTTP 请求",
"isInit": true,
"options": {
"uri": "https://www.taobao.com",
"params": {
"a": 1,
"b": true,
"c": "3"
}
}
},
{
"type": "http",
"id": "请求商家数据5是一个 HTTP 请求,是一个 HTTP 请求,是一个 HTTP 请求",
"isInit": false,
"options": {
"uri": "https://www.taobao.com",
"params": {
"a": 1,
"b": true,
"c": "3"
}
}
},
{
"type": "http",
"id": "请求商家数据6是一个 HTTP 请求,是一个 HTTP 请求,是一个 HTTP 请求",
"isInit": true, "isInit": true,
"options": { "options": {
"uri": "https://www.taobao.com", "uri": "https://www.taobao.com",

View File

@ -1,26 +1,10 @@
TODO ## 低代码引擎 - 数据源面板插件
---
* 多语言 对页面的数据源进行管理(新建,编辑,导入)。
* [later]表达式和其他类型的切换
* 现有场景代码的兼容
* class publich method bind issue
* ICON
* 支持变量
## 数据源面板
数据源管理
* 新建
* 编辑
* 导入
* 指定数据源类型
* 定制数据源导入插件
## 数据源类型定义 ## 数据源类型定义
内置变量http 和 mtop 类型,支持传入自定义类型。 内置 fetch 和 mtop 类型,支持传入自定义类型。
``` ```
type DataSourceType = { type DataSourceType = {
@ -29,9 +13,7 @@ type DataSourceType = {
}; };
``` ```
数据源类型需要在集团规范约束下扩展。 数据源类型需要在集团规范约束下扩展。目前只允许在 options 下添加扩展字段。
目前只允许在 options 下添加扩展字段。
比如 mtop 类型,需要添加 options.v (版本)字段。 比如 mtop 类型,需要添加 options.v (版本)字段。
@ -56,16 +38,8 @@ interface DataSourcePaneImportPluginComponentProps extends DataSourcePaneImportP
} }
``` ```
## 问题
* 变量,上下文放数据源里管理是否合适
* mockUrl 和 mockData
* 设计器的设计语言无法统一
## 插件开发 ## 插件开发
<https://yuque.antfin-inc.com/ali-lowcode/docs/ip4awq> [https://yuque.antfin-inc.com/ali-lowcode/docs/ip4awq](插件开发文档)。
## node 版本 本地开发需要在 v14.4.0 的 node 环境下进行。
v14.4.0

View File

@ -0,0 +1,18 @@
TODO
---
* 多语言
* ICON
* 支持变量
* 定制样式
* 不使用 bind
* 表达式 setter 的联想
* [later]表达式和其他类型的切换
* 变量,上下文的提案
* mock 的提案
## 问题
* 变量,上下文放数据源里管理是否合适
* mockUrl 和 mockData
* 设计器的设计语言无法统一

View File

@ -1,7 +1,6 @@
{ {
"plugins": [ "plugins": [
[ "build-plugin-component",
"build-plugin-component" "build-plugin-fusion"
]
] ]
} }

View File

@ -1,5 +1,6 @@
// @todo schema default // @todo schema default
import React, { PureComponent, ReactElement, FC } from 'react'; import React, { PureComponent, ReactElement, FC } from 'react';
import { Button } from '@alifd/next';
import { SchemaForm, FormButtonGroup, Submit } from '@formily/next'; import { SchemaForm, FormButtonGroup, Submit } from '@formily/next';
import { ArrayTable, Input, Switch, NumberPicker } from '@formily/next-components'; import { ArrayTable, Input, Switch, NumberPicker } from '@formily/next-components';
import _isPlainObject from 'lodash/isPlainObject'; import _isPlainObject from 'lodash/isPlainObject';
@ -164,8 +165,6 @@ export class DataSourceForm extends PureComponent<DataSourceFormProps, DataSourc
} }
}); });
debugger;
if (_get(formSchema, 'properties.options.properties.params')) { if (_get(formSchema, 'properties.options.properties.params')) {
formSchema.properties.options.properties.params = { formSchema.properties.options.properties.params = {
...formSchema.properties.options.properties.params, ...formSchema.properties.options.properties.params,
@ -247,7 +246,7 @@ export class DataSourceForm extends PureComponent<DataSourceFormProps, DataSourc
const { dataSource } = this.props; const { dataSource } = this.props;
return ( return (
<div className="lowcode-plugin-datasource-pane-datasource"> <div className="lowcode-plugin-datasource-form">
<SchemaForm <SchemaForm
onSubmit={this.handleFormSubmit} onSubmit={this.handleFormSubmit}
components={{ components={{
@ -258,13 +257,14 @@ export class DataSourceForm extends PureComponent<DataSourceFormProps, DataSourc
Switch, Switch,
JSFunction, JSFunction,
}} }}
labelCol={3} labelCol={4}
wrapperCol={21} wrapperCol={19}
schema={this.deriveSchema()} schema={this.deriveSchema()}
initialValues={this.deriveInitialData(dataSource)} initialValues={this.deriveInitialData(dataSource)}
> >
<FormButtonGroup offset={7}> <FormButtonGroup offset={4}>
<Submit></Submit> <Submit></Submit>
<Button onClick={this.handleCancel}></Button>
</FormButtonGroup> </FormButtonGroup>
</SchemaForm> </SchemaForm>
</div> </div>

View File

@ -0,0 +1,7 @@
.param-value {
display: flex;
flex-direction: row;
.param-value-type {
margin-right: 4px;
}
}

View File

@ -1,5 +1,5 @@
import React, { PureComponent, ReactElement, FC } from 'react'; import React, { PureComponent, ReactElement, FC } from 'react';
import { Button, Input, Radio, NumberPicker, Switch } from '@alifd/next'; import { Select, Input, Radio, NumberPicker, Switch } from '@alifd/next';
import { connect } from '@formily/react-schema-renderer'; import { connect } from '@formily/react-schema-renderer';
import _isPlainObject from 'lodash/isPlainObject'; import _isPlainObject from 'lodash/isPlainObject';
import _isArray from 'lodash/isArray'; import _isArray from 'lodash/isArray';
@ -10,21 +10,37 @@ import _get from 'lodash/get';
import _tap from 'lodash/tap'; import _tap from 'lodash/tap';
import { ExpressionSetter } from '@ali/lowcode-editor-setters'; import { ExpressionSetter } from '@ali/lowcode-editor-setters';
import './param-value.scss';
const { Group: RadioGroup } = Radio; const { Group: RadioGroup } = Radio;
type ParamValueType = 'string' | 'number' | 'boolean' | 'expression';
export interface ParamValueProps { export interface ParamValueProps {
className: string; className: string;
value: any; value: any;
onChange?: () => void; onChange?: () => void;
types: ParamValueType[];
} }
export interface ParamValueState { export interface ParamValueState {
type: 'string' | 'number' | 'boolean' | ''; type: 'string' | 'number' | 'boolean' | '';
} }
const TYPE_LABEL_MAP = {
string: '字符串',
number: '数字',
boolean: '布尔',
expression: '表达式',
};
class ParamValueComp extends PureComponent<ParamValueProps, ParamValueState> { class ParamValueComp extends PureComponent<ParamValueProps, ParamValueState> {
static isFieldComponent = true; static isFieldComponent = true;
static defaultProps = {
types: ['string', 'boolean', 'number', 'expression'],
};
state = { state = {
type: '', type: '',
}; };
@ -48,7 +64,7 @@ class ParamValueComp extends PureComponent<ParamValueProps, ParamValueState> {
// @todo 需要再 bind 一次? // @todo 需要再 bind 一次?
handleChange = (value) => { handleChange = (value) => {
this.props?.onChange(value); this.props?.onChange(value);
} };
componentDidUpdate(prevProps) { componentDidUpdate(prevProps) {
if (this.props.value !== prevProps.value) { if (this.props.value !== prevProps.value) {
@ -78,19 +94,46 @@ class ParamValueComp extends PureComponent<ParamValueProps, ParamValueState> {
}); });
}; };
renderTypeSelect = () => {
const { type } = this.state;
const { types } = this.props;
if (_isArray(types) && types.length > 2) {
return (
<Select
className="param-value-type"
dataSource={types.map((item) => ({
label: TYPE_LABEL_MAP[item],
value: item,
}))}
value={type}
/>
);
}
if (_isArray(types) && types.length > 1) {
return (
<RadioGroup
className="param-value-type"
shape="button"
size="small"
onChange={this.handleTypeChange}
value={type}
>
{types.map((item) => (
<Radio value={item}>TYPE_LABEL_MAP[item]</Radio>
))}
</RadioGroup>
);
}
return null;
};
render() { render() {
const { type } = this.state; const { type } = this.state;
const { value } = this.props; const { value } = this.props;
return ( return (
<div> <div className="param-value">
{ {this.renderTypeSelect()}
<RadioGroup shape="button" size="small" onChange={this.handleTypeChange}>
<Radio value="string"></Radio>
<Radio value="boolean"></Radio>
<Radio value="number"></Radio>
<Radio value="expression"></Radio>
</RadioGroup>
}
{type === 'string' && <Input onChange={this.handleChange.bind(this)} value={value} />} {type === 'string' && <Input onChange={this.handleChange.bind(this)} value={value} />}
{type === 'boolean' && <Switch onChange={this.handleChange.bind(this)} checked={value} />} {type === 'boolean' && <Switch onChange={this.handleChange.bind(this)} checked={value} />}
{type === 'number' && <NumberPicker onChange={this.handleChange.bind(this)} value={value} />} {type === 'number' && <NumberPicker onChange={this.handleChange.bind(this)} value={value} />}

View File

@ -0,0 +1,15 @@
.lowcode-plugin-datasource-import-plugin-code {
height: unquote("calc(100vh - 48px - 48px - 42px)");
overflow: auto;
.error-msg {
line-height: 24px;
color: #f60;
font-size: 12px;
}
.btns {
margin-top: 8px;
}
.next-btn {
margin-right: 4px;
}
}

View File

@ -14,6 +14,8 @@ import { DataSourceConfig } from '@ali/lowcode-types';
import Ajv from 'ajv'; import Ajv from 'ajv';
import { DataSourcePaneImportPluginComponentProps } from '../types'; import { DataSourcePaneImportPluginComponentProps } from '../types';
import './code.scss';
export interface DataSourceImportPluginCodeProps extends DataSourcePaneImportPluginComponentProps { export interface DataSourceImportPluginCodeProps extends DataSourcePaneImportPluginComponentProps {
defaultValue?: DataSourceConfig[]; defaultValue?: DataSourceConfig[];
} }
@ -115,11 +117,11 @@ export class DataSourceImportPluginCode extends PureComponent<
const { code, isCodeValid } = this.state; const { code, isCodeValid } = this.state;
return ( return (
<div> <div className="lowcode-plugin-datasource-import-plugin-code">
<MonacoEditor <MonacoEditor
theme="vs-dark" theme="vs-dark"
width={800} width={800}
height={600} height={400}
defaultValue={code} defaultValue={code}
language="json" language="json"
onChange={this.handleEditorChange} onChange={this.handleEditorChange}
@ -127,10 +129,10 @@ export class DataSourceImportPluginCode extends PureComponent<
formatOnType formatOnType
formatOnPaste formatOnPaste
/> />
{!isCodeValid && <p></p>} {!isCodeValid && <p className="error-msg"></p>}
<p> <p className="btns">
<Button onClick={onCancel}></Button> <Button onClick={onCancel}></Button>
<Button onClick={this.handleComplete}></Button> <Button type="primary" onClick={this.handleComplete}></Button>
</p> </p>
</div> </div>
); );

View File

@ -12,7 +12,86 @@
} }
.lowcode-plugin-datasource-pane-list { .lowcode-plugin-datasource-pane-list {
.next-virtual-list-wrapper { margin: 8px;
min-height: 400px; .next-search {
width: 100%;
.next-search-left {
height: 28px !important;
border-top-left-radius: 3px;
border-bottom-left-radius: 3px;
.next-before {
height: 28px !important;
.next-select {
height: 28px !important;
}
}
.next-search-input {
height: 28px !important;
input {
height: 28px !important;
}
}
.next-input {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
}
.next-after {
// height: 28px !important;
.next-btn {
height: 30px !important;
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
.next-icon:before {
font-size: 12px;
}
}
}
}
.datasource-list {
margin-top: 8px;
height: unquote("calc(100vh - 48px - 48px - 42px - 28px - 8px - 8px)");
overflow: auto;
.next-virtual-list-wrapper > div > ul > li {
border-top: 1px solid #ddd;
&:first-child {
border-top: none;
}
}
}
.datasource-item {
margin: 8px;
.datasource-item-title {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
height: 28px;
.datasource-item-id {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 12px;
}
.next-btn {
margin-left: 4px;
}
}
.datasource-item-desc {
.next-tag {
margin-right: 4px;
}
}
}
}
.lowcode-plugin-datasource-form {
height: unquote("calc(100vh - 48px - 48px - 42px)");
overflow: auto;
.next-form-item {
.next-form-item-control {
}
} }
} }

View File

@ -4,6 +4,8 @@ import { DataSourcePane } from './pane';
import { DataSourcePaneImportPlugin, DataSourceType } from './types'; import { DataSourcePaneImportPlugin, DataSourceType } from './types';
import { DataSourceImportPluginCode } from './import-plugins'; import { DataSourceImportPluginCode } from './import-plugins';
import './index.scss';
export { DataSourceImportPluginCode }; export { DataSourceImportPluginCode };
const PLUGIN_NAME = 'dataSourcePane'; const PLUGIN_NAME = 'dataSourcePane';

View File

@ -64,57 +64,77 @@ export default class DataSourceList extends PureComponent<DataSourceListProps, D
?.filter((item) => (keyword ? item.id.indexOf(keyword) !== -1 : true)) ?.filter((item) => (keyword ? item.id.indexOf(keyword) !== -1 : true))
?.map((item) => ( ?.map((item) => (
<li key={item.id}> <li key={item.id}>
<Balloon <div className="datasource-item">
trigger={ <div className="datasource-item-title">
<div> <div className="datasource-item-id" title={item.id}>
<Tag size="small">{item.type}</Tag>
<Tag size="small">{item.isInit ? '自动' : '手动'}</Tag>
{item.id} {item.id}
<Button onClick={this.handleEditDataSource.bind(this, item.id)}></Button>
<Button onClick={this.handleDuplicateDataSource.bind(this, item.id)}></Button>
<Button onClick={this.handleRemoveDataSource.bind(this, item.id)}></Button>
</div> </div>
} <Balloon
align="r" trigger={<Button size="small"></Button>}
alignEdge align="b"
triggerType="hover" alignEdge
style={{ width: 300 }} triggerType="hover"
> style={{ width: 300 }}
<Table >
dataSource={_tap(Object.keys(item.options || {}).reduce<TableRow[]>((acc, cur) => { <Table
// @todo 这里的 ts 处理得不好 dataSource={_tap(
if (_isPlainObject(item.options[cur])) { Object.keys(item.options || {}).reduce<TableRow[]>((acc, cur) => {
Object.keys(item?.options?.[cur] || {}).forEach((curInOption) => { // @todo 这里的 ts 处理得不好
acc.push({ if (_isPlainObject(item.options[cur])) {
label: `${cur}.${curInOption}`, Object.keys(item?.options?.[cur] || {}).forEach((curInOption) => {
value: (item?.options?.[cur] as any)?.[curInOption], acc.push({
}); label: `${cur}.${curInOption}`,
}); value: (item?.options?.[cur] as any)?.[curInOption],
} else if (!_isNil(item.options[cur])) { });
// @todo 排除 null });
acc.push({ } else if (!_isNil(item.options[cur])) {
label: cur, // @todo 排除 null
value: item.options[cur], acc.push({
}); label: cur,
} value: item.options[cur],
return acc; });
}, []), console.log)} }
> return acc;
<TableCol title="" dataIndex="label" /> }, []),
<TableCol console.log,
title="" )}
dataIndex="value" >
cell={(val: any) => ( <TableCol title="" dataIndex="label" />
<div> <TableCol
<Tag> title=""
{_isBoolean(val) ? 'bool' : _isNumber(val) ? 'number' : _isPlainObject(val) ? 'obj' : 'string'} dataIndex="value"
</Tag> cell={(val: any) => (
{val.toString()} <div>
</div> <Tag>
)} {_isBoolean(val)
/> ? 'bool'
</Table> : _isNumber(val)
</Balloon> ? 'number'
: _isPlainObject(val)
? 'obj'
: 'string'}
</Tag>
{val.toString()}
</div>
)}
/>
</Table>
</Balloon>
<Button size="small" onClick={this.handleEditDataSource.bind(this, item.id)}>
</Button>
<Button size="small" onClick={this.handleDuplicateDataSource.bind(this, item.id)}>
</Button>
<Button size="small" onClick={this.handleRemoveDataSource.bind(this, item.id)}>
</Button>
</div>
<div className="datasource-item-desc">
<Tag size="small">{item.type}</Tag>
<Tag size="small">{item.isInit ? '自动' : '手动'}</Tag>
</div>
</div>
</li> </li>
)) || [] )) || []
); );
@ -136,7 +156,9 @@ export default class DataSourceList extends PureComponent<DataSourceListProps, D
}))} }))}
onFilterChange={this.handleSearchFilterChange} onFilterChange={this.handleSearchFilterChange}
/> />
<VirtualList>{this.deriveListDataSource()}</VirtualList> <div className="datasource-list">
<VirtualList>{this.deriveListDataSource()}</VirtualList>
</div>
</div> </div>
); );
} }

View File

@ -3,7 +3,7 @@
*/ */
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { DataSource, DataSourceConfig } from '@ali/lowcode-types'; import { DataSource, DataSourceConfig } from '@ali/lowcode-types';
import { Tab, Button, MenuButton, Message } from '@alifd/next'; import { Tab, Button, MenuButton, Message, Dialog } from '@alifd/next';
import _cloneDeep from 'lodash/cloneDeep'; import _cloneDeep from 'lodash/cloneDeep';
import _uniqueId from 'lodash/uniqueId'; import _uniqueId from 'lodash/uniqueId';
import _startsWith from 'lodash/startsWith'; import _startsWith from 'lodash/startsWith';
@ -63,14 +63,14 @@ export class DataSourcePane extends PureComponent<DataSourcePaneProps, DataSourc
constructor(props) { constructor(props) {
super(props); super(props);
this.handleDataSourceListChange = this.handleDataSourceListChange.bind(this); // this.handleDataSourceListChange = this.handleDataSourceListChange.bind(this);
this.handleImportDataSourceList = this.handleImportDataSourceList.bind(this); // this.handleImportDataSourceList = this.handleImportDataSourceList.bind(this);
this.handleCreateDataSource = this.handleCreateDataSource.bind(this); // this.handleCreateDataSource = this.handleCreateDataSource.bind(this);
this.handleUpdateDataSource = this.handleUpdateDataSource.bind(this); // this.handleUpdateDataSource = this.handleUpdateDataSource.bind(this);
this.handleRemoveDataSource = this.handleRemoveDataSource.bind(this); // this.handleRemoveDataSource = this.handleRemoveDataSource.bind(this);
this.handleDuplicateDataSource = this.handleDuplicateDataSource.bind(this); // this.handleDuplicateDataSource = this.handleDuplicateDataSource.bind(this);
this.handleEditDataSource = this.handleEditDataSource.bind(this); // this.handleEditDataSource = this.handleEditDataSource.bind(this);
this.handleTabChange = this.handleTabChange.bind(this); // this.handleTabChange = this.handleTabChange.bind(this);
} }
handleDataSourceListChange = (dataSourceList?: DataSourceConfig[]) => { handleDataSourceListChange = (dataSourceList?: DataSourceConfig[]) => {
@ -83,31 +83,66 @@ export class DataSourcePane extends PureComponent<DataSourcePaneProps, DataSourc
}; };
handleImportDataSourceList = (toImport: DataSourceConfig[]) => { handleImportDataSourceList = (toImport: DataSourceConfig[]) => {
this.closeTab(TAB_ITEM_IMPORT); const importDataSourceList = () => {
this.setState( this.closeTab(TAB_ITEM_IMPORT);
({ dataSourceList }) => ({ this.setState(
dataSourceList: dataSourceList.concat(toImport), ({ dataSourceList }) => ({
}), dataSourceList: dataSourceList.concat(toImport),
() => { }),
this.handleDataSourceListChange(); () => {
}, this.handleDataSourceListChange();
},
);
};
if (!_isArray(toImport) || toImport.length === 0) {
Message.error('没有找到可导入的数据源');
return;
}
const repeatedDataSourceList = toImport.filter(
item => !!this.state.dataSourceList.find(
dataSource => dataSource.id === item.id
)
); );
if (repeatedDataSourceList.length > 0) {
Dialog.confirm({
content: `数据源(${repeatedDataSourceList.map(item => item.id).join('')})已存在,如果导入会替换原数据源,是否继续?`,
onOk: () => {
importDataSourceList();
}
});
return;
}
importDataSourceList();
}; };
handleCreateDataSource = (toCreate: DataSourceConfig) => { handleCreateDataSource = (toCreate: DataSourceConfig) => {
this.closeTab(TAB_ITEM_CREATE); const create = () => {
this.setState( this.closeTab(TAB_ITEM_CREATE);
({ dataSourceList }) => ({ this.setState(
dataSourceList: dataSourceList.concat([ ({ dataSourceList }) => ({
{ dataSourceList: dataSourceList.concat([
...toCreate, {
}, ...toCreate,
]), },
}), ]),
() => { }),
this.handleDataSourceListChange(); () => {
}, this.handleDataSourceListChange();
); },
);
};
if (this.state.dataSourceList.find(
dataSource => dataSource.id === toCreate.id
)) {
Dialog.confirm({
content: `数据源(${toCreate.id})已存在,如果导入会替换原数据源,是否继续?`,
onOk: () => {
create();
}
});
return;
}
create();
}; };
handleUpdateDataSource = (toUpdate: DataSourceConfig) => { handleUpdateDataSource = (toUpdate: DataSourceConfig) => {
@ -130,14 +165,22 @@ export class DataSourcePane extends PureComponent<DataSourcePaneProps, DataSourc
}; };
handleRemoveDataSource = (dataSourceId: string) => { handleRemoveDataSource = (dataSourceId: string) => {
this.setState( const remove = () => {
({ dataSourceList }) => ({ this.setState(
dataSourceList: dataSourceList.filter((item) => item.id !== dataSourceId), ({ dataSourceList }) => ({
}), dataSourceList: dataSourceList.filter((item) => item.id !== dataSourceId),
() => { }),
this.handleDataSourceListChange(); () => {
}, this.handleDataSourceListChange();
); },
);
};
Dialog.confirm({
content: `确定要删除吗?`,
onOk: () => {
remove();
}
});
}; };
handleDuplicateDataSource = (dataSourceId: string) => { handleDuplicateDataSource = (dataSourceId: string) => {
@ -233,7 +276,7 @@ export class DataSourcePane extends PureComponent<DataSourcePaneProps, DataSourc
})); }));
this.setState({ activeTabKey: TAB_ITEM_IMPORT }); this.setState({ activeTabKey: TAB_ITEM_IMPORT });
} else { } else {
Message.notice('当前已有一个导入数据源的 TAB 被大家'); Message.notice('当前已有一个导入数据源的 TAB');
} }
}; };
@ -256,21 +299,21 @@ export class DataSourcePane extends PureComponent<DataSourcePaneProps, DataSourc
// @todo onSelect 不行? // @todo onSelect 不行?
return [ return [
_isArray(dataSourceTypes) && dataSourceTypes.length > 1 ? ( _isArray(dataSourceTypes) && dataSourceTypes.length > 1 ? (
<MenuButton size="small" label="新建" onItemClick={this.openCreateDataSourceTab}> <MenuButton label="新建" onItemClick={this.openCreateDataSourceTab}>
{dataSourceTypes.map((type) => ( {dataSourceTypes.map((type) => (
<MenuButtonItem key={type.type}>{type.type}</MenuButtonItem> <MenuButtonItem key={type.type}>{type.type}</MenuButtonItem>
))} ))}
</MenuButton> </MenuButton>
) : _isArray(dataSourceTypes) && dataSourceTypes.length > 1 ? ( ) : _isArray(dataSourceTypes) && dataSourceTypes.length === 1 ? (
<Button onClick={this.openImportDataSourceTab.bind(this, dataSourceTypes[0])}></Button> <Button onClick={this.openCreateDataSourceTab.bind(this, dataSourceTypes[0].type)}></Button>
) : null, ) : null,
_isArray(importPlugins) && importPlugins.length > 1 ? ( _isArray(importPlugins) && importPlugins.length > 1 ? (
<MenuButton size="small" label="导入" onItemClick={this.openImportDataSourceTab}> <MenuButton label="导入" onItemClick={this.openImportDataSourceTab}>
{importPlugins.map((plugin) => ( {importPlugins.map((plugin) => (
<MenuButtonItem key={plugin.name}>{plugin.name}</MenuButtonItem> <MenuButtonItem key={plugin.name}>{plugin.name}</MenuButtonItem>
))} ))}
</MenuButton> </MenuButton>
) : _isArray(importPlugins) && importPlugins.length > 1 ? ( ) : _isArray(importPlugins) && importPlugins.length === 1 ? (
<Button onClick={this.openImportDataSourceTab.bind(this, importPlugins[0].name)}></Button> <Button onClick={this.openImportDataSourceTab.bind(this, importPlugins[0].name)}></Button>
) : null, ) : null,
]; ];

View File

@ -1,6 +1,6 @@
{ {
"extends": "../../tsconfig.json", "extends": "../../tsconfig.json",
"lib": ["es6", "dom"], "lib": ["esnext", "dom"],
"compilerOptions": { "compilerOptions": {
"outDir": "lib" "outDir": "lib"
}, },