新增克隆相关功能UI

This commit is contained in:
keran 2019-05-27 22:33:11 +08:00
parent 8e92e5a907
commit 72d6987b3b
3 changed files with 353 additions and 93 deletions

View File

@ -245,6 +245,23 @@ const I18N_CONF = {
failureEntries: 'Failure entries',
unprocessedEntries: 'Unprocessed entries',
skippedEntries: 'skipped entries',
exportSelected: 'Export selected configs',
clone: 'Clone',
exportSelectedAlertTitle: 'Export config',
exportSelectedAlertContent: 'please select the configuration to export',
cloneSucc: 'The clone was successful',
cloneAbort: 'Clone abort',
cloneSuccBegin: 'The clone was successful,with ',
cloneSuccEnd: 'configuration items cloned',
cloneFail: 'Clone failed',
getNamespaceFailed: 'get the namespace failed',
startCloning: 'Start Clone',
cloningConfiguration: 'Clone config',
source: 'Source :',
configurationNumber: 'Items:',
target: 'Target:',
selectNamespace: 'Select Namespace',
selectedEntry: '| Selected Entry',
},
NewConfig: {
newListingMain: 'Create Configuration',

View File

@ -243,6 +243,23 @@ const I18N_CONF = {
failureEntries: '失败的条目',
unprocessedEntries: '未处理的条目',
skippedEntries: '跳过的条目',
exportSelected: '导出选中的配制',
clone: '克隆',
exportSelectedAlertTitle: '配制导出',
exportSelectedAlertContent: '请选择要导出的配制',
cloneSucc: '克隆成功',
cloneAbort: '克隆终止',
cloneSuccBegin: '克隆成功,克隆了',
cloneSuccEnd: '项配制',
cloneFail: '克隆失败',
getNamespaceFailed: '获取命名空间失败',
startCloning: '开始克隆',
cloningConfiguration: '克隆配制',
source: '源空间',
configurationNumber: '配置数量',
target: '目标空间',
selectNamespace: '请选择命名空间',
selectedEntry: '| 选中的条目',
},
NewConfig: {
newListingMain: '新建配置',

View File

@ -45,6 +45,7 @@ import { LANGUAGE_KEY } from '../../../constants';
const { Panel } = Collapse;
const { Row, Col } = Grid;
const configsTableSelected = new Map();
@ConfigProvider.config
class ConfigurationManagement extends React.Component {
@ -672,24 +673,280 @@ class ConfigurationManagement extends React.Component {
}
exportData() {
let url =
'v1/cs/configs?export=true&group=' +
this.group +
'&tenant=' +
getParams('namespace') +
'&appName=' +
this.appName +
'&ids=';
let url = `v1/cs/configs?export=true&group=${this.group}&tenant=${getParams(
'namespace'
)}&appName=${this.appName}&ids=`;
window.location.href = url;
}
exportSelectedData() {
const { locale = {} } = this.props;
if (configsTableSelected.size === 0) {
Dialog.alert({
title: locale.exportSelectedAlertTitle,
content: locale.exportSelectedAlertContent,
});
} else {
let idsStr = '';
configsTableSelected.forEach((value, key, map) => {
idsStr = `${idsStr + key},`;
});
let url = `v1/cs/configs?export=true&group=&tenant=&appName=&ids=${idsStr}`;
window.location.href = url;
}
}
cloneSelectedDataConfirm() {
const { locale = {} } = this.props;
const self = this;
const { init } = self.field;
self.field.setValue('sameConfigPolicy', 'ABORT');
self.field.setValue('cloneTargetSpace', undefined);
if (configsTableSelected.size === 0) {
Dialog.alert({
title: locale.exportSelectedAlertTitle,
content: locale.exportSelectedAlertContent,
});
return;
}
request({
url: 'v1/console/namespaces?namespaceId=',
beforeSend() {
self.openLoading();
},
success(data) {
if (!data || data.code !== 200 || !data.data) {
Dialog.alert({
title: locale.getNamespaceFailed,
content: locale.getNamespaceFailed,
});
}
let namespaces = data.data;
let namespaceSelectData = [];
namespaces.forEach(item => {
if (self.state.nownamespace_id !== item.namespace) {
let dataItem = {};
if (item.namespaceShowName === 'public') {
dataItem.label = 'public | public';
dataItem.value = 'public';
} else {
dataItem.label = `${item.namespaceShowName} | ${item.namespace}`;
dataItem.value = item.namespace;
}
namespaceSelectData.push(dataItem);
}
});
const cloneConfirm = Dialog.confirm({
title: locale.cloningConfiguration,
footer: false,
content: (
<div>
<div style={{ marginBottom: 10 }}>
<span style={{ color: '#999', marginRight: 5 }}>{locale.source}</span>
<span style={{ color: '#49D2E7' }}>{self.state.nownamespace_name} </span>|{' '}
{self.state.nownamespace_id}
</div>
<div style={{ marginBottom: 10 }}>
<span style={{ color: '#999', marginRight: 5 }}>{locale.configurationNumber}</span>
<span style={{ color: '#49D2E7' }}>{configsTableSelected.size} </span>
{locale.selectedEntry}
</div>
<div style={{ marginBottom: 10 }}>
<span style={{ color: 'red', marginRight: 2, marginLeft: -10 }}>{'*'}</span>
<span style={{ color: '#999', marginRight: 5 }}>{locale.target}</span>
<Select
style={{ width: 450 }}
placeholder={locale.selectNamespace}
size={'medium'}
hasArrow
showSearch
hasClear={false}
mode="single"
dataSource={namespaceSelectData}
onChange={(value, actionType, item) => {
if (value) {
document.getElementById('cloneTargetSpaceSelectErr').style.display = 'none';
self.field.setValue('cloneTargetSpace', value);
}
}}
/>
<br />
<span id={'cloneTargetSpaceSelectErr'} style={{ color: 'red', display: 'none' }}>
{locale.selectNamespace}
</span>
</div>
<div style={{ marginBottom: 10 }}>
<span style={{ color: '#999', marginRight: 5 }}>{locale.samePreparation}:</span>
<Select
style={{ width: 130 }}
size={'medium'}
hasArrow
mode="single"
filterLocal={false}
defaultValue={'ABORT'}
dataSource={[
{
label: locale.abortImport,
value: 'ABORT',
},
{
label: locale.skipImport,
value: 'SKIP',
},
{
label: locale.overwriteImport,
value: 'OVERWRITE',
},
]}
hasClear={false}
onChange={(value, actionType, item) => {
if (value) {
self.field.setValue('sameConfigPolicy', value);
}
}}
/>
</div>
<div>
<Button
type={'primary'}
style={{ marginRight: 10 }}
onClick={() => {
if (!self.field.getValue('cloneTargetSpace')) {
document.getElementById('cloneTargetSpaceSelectErr').style.display = 'inline';
return;
} else {
document.getElementById('cloneTargetSpaceSelectErr').style.display = 'none';
}
let idsStr = '';
configsTableSelected.forEach((value, key, map) => {
idsStr = `${idsStr + key},`;
});
let cloneTargetSpace = self.field.getValue('cloneTargetSpace');
let sameConfigPolicy = self.field.getValue('sameConfigPolicy');
request({
url: `v1/cs/configs?clone=true&tenant=${cloneTargetSpace}&policy=${sameConfigPolicy}&ids=${idsStr}`,
beforeSend() {
self.openLoading();
},
success(ret) {
self.processImportAndCloneResult(ret, locale, cloneConfirm, false);
},
error(data) {
self.setState({
dataSource: [],
total: 0,
currentPage: 0,
});
},
complete() {
self.closeLoading();
},
});
}}
data-spm-click={'gostr=/aliyun;locaid=doClone'}
>
{locale.startCloning}
</Button>
</div>
</div>
),
});
},
error(data) {
self.setState({
dataSource: [],
total: 0,
currentPage: 0,
});
},
complete() {
self.closeLoading();
},
});
}
processImportAndCloneResult(ret, locale, confirm, isImport) {
const resultCode = ret.code;
if (resultCode === 200) {
confirm.hide();
if (ret.data.failData && ret.data.failData.length > 0) {
Dialog.alert({
title: isImport ? locale.importAbort : locale.cloneAbort,
content: (
<div style={{ width: '500px' }}>
<h4>
{locale.conflictConfig}{ret.data.failData[0].group}/{ret.data.failData[0].dataId}
</h4>
<div style={{ marginTop: 20 }}>
<h5>
{locale.failureEntries}: {ret.data.failData.length}
</h5>
<Table dataSource={ret.data.failData}>
<Table.Column title="Data Id" dataIndex="dataId" />
<Table.Column title="Group" dataIndex="group" />
</Table>
</div>
<div>
<h5>
{locale.unprocessedEntries}: {ret.data.skipData ? ret.data.skipData : 0}
</h5>
<Table dataSource={ret.data.skipData}>
<Table.Column title="Data Id" dataIndex="dataId" />
<Table.Column title="Group" dataIndex="group" />
</Table>
</div>
</div>
),
});
} else if (ret.data.skipCount && ret.data.skipCount > 0) {
Dialog.alert({
title: isImport ? locale.importSucc : locale.cloneSucc,
content: (
<div style={{ width: '500px' }}>
<div>
<h5>
{locale.skippedEntries}: {ret.data.skipData.length}
</h5>
<Table dataSource={ret.data.skipData}>
<Table.Column title="Data Id" dataIndex="dataId" />
<Table.Column title="Group" dataIndex="group" />
</Table>
</div>
</div>
),
});
} else {
let message = `${isImport ? locale.importSuccBegin : locale.cloneSuccBegin}${
ret.data.succCount
}${isImport ? locale.importSuccEnd : locale.cloneSuccEnd}`;
Message.success(message);
}
this.getData();
} else {
let alertContent = isImport ? locale.importFailMsg : locale.cloneFailMsg;
if (resultCode === 5001) {
alertContent = locale.namespaceNotExist;
}
if (resultCode === 5002) {
alertContent = locale.metadataIllegal;
}
if (resultCode === 5003 || resultCode === 5004 || resultCode === 5005) {
alertContent = locale.importDataValidationError;
}
Dialog.alert({
title: isImport ? locale.importFail : locale.cloneFail,
content: alertContent,
});
}
}
importData() {
const { locale = {} } = this.props;
const self = this;
self.field.setValue('sameConfigPolicy', 'ABORT');
const uploadProps = {
accept: 'application/zip',
action: 'v1/cs/configs?import=true&namespace=' + getParams('namespace'),
action: `v1/cs/configs?import=true&namespace=${getParams('namespace')}`,
data: {
policy: self.field.getValue('sameConfigPolicy'),
},
@ -700,79 +957,7 @@ class ConfigurationManagement extends React.Component {
return options;
},
onSuccess(ret) {
const resultCode = ret.response.code;
if (resultCode === 200) {
importConfirm.hide();
if (ret.response.data.failData && ret.response.data.failData.length > 0) {
Dialog.alert({
title: locale.importAbort,
content: (
<div style={{ width: '500px' }}>
<h4>
{locale.conflictConfig}{ret.response.data.failData[0].group}/
{ret.response.data.failData[0].dataId}
</h4>
<div style={{ marginTop: 20 }}>
<h5>
{locale.failureEntries}: {ret.response.data.failData.length}
</h5>
<Table dataSource={ret.response.data.failData}>
<Table.Column title="Data Id" dataIndex="dataId" />
<Table.Column title="Group" dataIndex="group" />
</Table>
</div>
<div>
<h5>
{locale.unprocessedEntries}:{' '}
{ret.response.data.skipData ? ret.response.data.skipData : 0}
</h5>
<Table dataSource={ret.response.data.skipData}>
<Table.Column title="Data Id" dataIndex="dataId" />
<Table.Column title="Group" dataIndex="group" />
</Table>
</div>
</div>
),
});
} else if (ret.response.data.skipCount && ret.response.data.skipCount > 0) {
Dialog.alert({
title: locale.importSucc,
content: (
<div style={{ width: '500px' }}>
<div>
<h5>
{locale.skippedEntries}: {ret.response.data.skipData.length}
</h5>
<Table dataSource={ret.response.data.skipData}>
<Table.Column title="Data Id" dataIndex="dataId" />
<Table.Column title="Group" dataIndex="group" />
</Table>
</div>
</div>
),
});
} else {
let message =
locale.importSuccBegin + ret.response.data.succCount + locale.importSuccEnd;
Message.success(message);
}
self.getData();
} else {
let alertContent = locale.importFailMsg;
if (resultCode === 5001) {
alertContent = locale.namespaceNotExist;
}
if (resultCode === 5002) {
alertContent = locale.metadataIllegal;
}
if (resultCode === 5003 || resultCode === 5004 || resultCode === 5005) {
alertContent = locale.importDataValidationError;
}
Dialog.alert({
title: locale.importFail,
content: alertContent,
});
}
self.processImportAndCloneResult(ret.response, locale, importConfirm, true);
},
onError(err) {
Dialog.alert({
@ -786,7 +971,6 @@ class ConfigurationManagement extends React.Component {
footer: false,
content: (
<div>
<h3>{this.state.isok ? locale.deletedSuccessfully : locale.deleteFailed}</h3>
<div style={{ marginBottom: 10 }}>
<span style={{ color: '#999', marginRight: 5 }}>{locale.targetNamespace}:</span>
<span style={{ color: '#49D2E7' }}>{this.state.nownamespace_name} </span>|{' '}
@ -840,6 +1024,24 @@ class ConfigurationManagement extends React.Component {
});
}
configsTableOnSelect(selected, record, records) {
if (selected) {
configsTableSelected.set(record.id, record);
} else {
configsTableSelected.delete(record.id);
}
}
configsTableOnSelectAll(selected, records) {
if (selected) {
records.forEach((record, i) => {
configsTableSelected.set(record.id, record);
});
} else {
configsTableSelected.clear();
}
}
render() {
const { locale = {} } = this.props;
return (
@ -1037,6 +1239,10 @@ class ConfigurationManagement extends React.Component {
fixedHeader
maxBodyHeight={400}
ref={'dataTable'}
rowSelection={{
onSelect: this.configsTableOnSelect,
onSelectAll: this.configsTableOnSelectAll,
}}
>
<Table.Column title={'Data Id'} dataIndex={'dataId'} />
<Table.Column title={'Group'} dataIndex={'group'} />
@ -1049,16 +1255,36 @@ class ConfigurationManagement extends React.Component {
</Table>
{this.state.dataSource.length > 0 && (
<div style={{ marginTop: 10, overflow: 'hidden' }}>
<Pagination
style={{ float: 'right' }}
pageSizeList={[10, 20, 30]}
pageSizeSelector={'dropdown'}
onPageSizeChange={this.handlePageSizeChange.bind(this)}
current={this.state.currentPage}
total={this.state.total}
pageSize={this.state.pageSize}
onChange={this.changePage.bind(this)}
/>
<div style={{ float: 'left' }}>
<Button
type={'primary'}
style={{ marginLeft: 60, marginRight: 10 }}
onClick={this.exportSelectedData.bind(this)}
data-spm-click={'gostr=/aliyun;locaid=configsExport'}
>
{locale.exportSelected}
</Button>
<Button
type={'primary'}
style={{ marginRight: 10 }}
onClick={this.cloneSelectedDataConfirm.bind(this)}
data-spm-click={'gostr=/aliyun;locaid=configsClone'}
>
{locale.clone}
</Button>
</div>
<div style={{ float: 'right' }}>
<Pagination
style={{ float: 'right' }}
pageSizeList={[10, 20, 30]}
pageSizeSelector={'dropdown'}
onPageSizeChange={this.handlePageSizeChange.bind(this)}
current={this.state.currentPage}
total={this.state.total}
pageSize={this.state.pageSize}
onChange={this.changePage.bind(this)}
/>
</div>
</div>
)}
</div>