Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Same namespace clone#2171 #2194

Merged
merged 7 commits into from
Jan 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import com.alibaba.nacos.config.server.constant.Constants;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.config.server.controller.parameters.SameNamespaceCloneConfigBean;
import com.alibaba.nacos.config.server.model.*;
import com.alibaba.nacos.config.server.result.ResultBuilder;
import com.alibaba.nacos.config.server.result.code.ResultCodeEnum;
Expand Down Expand Up @@ -46,6 +47,7 @@
import java.net.URLDecoder;
import java.sql.Timestamp;
import java.util.*;
import java.util.stream.Collectors;

import static com.alibaba.nacos.core.utils.SystemUtils.LOCAL_IP;

Expand All @@ -66,7 +68,7 @@ public class ConfigController {

private static final String EXPORT_CONFIG_FILE_NAME_EXT = ".zip";

private static final String EXPORT_CONFIG_FILE_NAME_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
private static final String EXPORT_CONFIG_FILE_NAME_DATE_FORMAT = "yyyyMMddHHmmss";

private final ConfigServletInner inner;

Expand Down Expand Up @@ -525,14 +527,20 @@ public RestResult<Map<String, Object>> importAndPublishConfig(HttpServletRequest
return ResultBuilder.buildSuccessResult("导入成功", saveResult);
}

@GetMapping(params = "clone=true")
@PostMapping(params = "clone=true")
public RestResult<Map<String, Object>> cloneConfig(HttpServletRequest request,
@RequestParam(value = "src_user", required = false) String srcUser,
@RequestParam(value = "tenant", required = true) String namespace,
@RequestParam(value = "ids", required = true) List<Long> ids,
@RequestBody(required = true)
List<SameNamespaceCloneConfigBean> configBeansList,
@RequestParam(value = "policy", defaultValue = "ABORT")
SameConfigPolicy policy) throws NacosException {
Map<String, Object> failedData = new HashMap<>(4);
if(CollectionUtils.isEmpty(configBeansList)){
failedData.put("succCount", 0);
return ResultBuilder.buildResult(ResultCodeEnum.NO_SELECTED_CONFIG, failedData);
}
configBeansList.removeAll(Collections.singleton(null));

if (NAMESPACE_PUBLIC_KEY.equalsIgnoreCase(namespace)) {
namespace = "";
Expand All @@ -541,8 +549,14 @@ public RestResult<Map<String, Object>> cloneConfig(HttpServletRequest request,
return ResultBuilder.buildResult(ResultCodeEnum.NAMESPACE_NOT_EXIST, failedData);
}

ids.removeAll(Collections.singleton(null));
List<ConfigAllInfo> queryedDataList = persistService.findAllConfigInfo4Export(null, null, null, null, ids);
List<Long> idList = new ArrayList<>(configBeansList.size());
Map<Long, SameNamespaceCloneConfigBean> configBeansMap = configBeansList.stream()
.collect(Collectors.toMap(SameNamespaceCloneConfigBean::getCfgId, cfg -> {
idList.add(cfg.getCfgId());
return cfg;
},(k1, k2) -> k1));

List<ConfigAllInfo> queryedDataList = persistService.findAllConfigInfo4Export(null, null, null, null, idList);

if (queryedDataList == null || queryedDataList.isEmpty()) {
failedData.put("succCount", 0);
Expand All @@ -552,11 +566,12 @@ public RestResult<Map<String, Object>> cloneConfig(HttpServletRequest request,
List<ConfigAllInfo> configInfoList4Clone = new ArrayList<>(queryedDataList.size());

for (ConfigAllInfo ci : queryedDataList) {
SameNamespaceCloneConfigBean prarmBean = configBeansMap.get(ci.getId());
ConfigAllInfo ci4save = new ConfigAllInfo();
ci4save.setTenant(namespace);
ci4save.setType(ci.getType());
ci4save.setGroup(ci.getGroup());
ci4save.setDataId(ci.getDataId());
ci4save.setGroup((prarmBean != null && StringUtils.isNotBlank(prarmBean.getGroup())) ? prarmBean.getGroup() : ci.getGroup());
ci4save.setDataId((prarmBean != null && StringUtils.isNotBlank(prarmBean.getDataId())) ? prarmBean.getDataId() : ci.getDataId());
ci4save.setContent(ci.getContent());
if (StringUtils.isNotBlank(ci.getAppName())) {
ci4save.setAppName(ci.getAppName());
Expand All @@ -580,7 +595,7 @@ public RestResult<Map<String, Object>> cloneConfig(HttpServletRequest request,
configInfo.getTenant(), requestIpApp, time.getTime(),
LOCAL_IP, ConfigTraceService.PERSISTENCE_EVENT_PUB, configInfo.getContent());
}
return ResultBuilder.buildSuccessResult("导入成功", saveResult);
return ResultBuilder.buildSuccessResult("克隆成功", saveResult);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.config.server.controller.parameters;

/**
* @author klw(213539 @ qq.com)
* @ClassName: SameNamespaceCloneConfigBean
* @Description: 同namespace克隆接口的配制bean
* @date 2019/12/13 16:10
*/
public class SameNamespaceCloneConfigBean {

private Long cfgId;

private String dataId;

private String group;

public Long getCfgId() {
return cfgId;
}

public void setCfgId(Long cfgId) {
this.cfgId = cfgId;
}

public String getDataId() {
return dataId;
}

public void setDataId(String dataId) {
this.dataId = dataId;
}

public String getGroup() {
return group;
}

public void setGroup(String group) {
this.group = group;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ public enum ResultCodeEnum implements IResultCode {

DATA_EMPTY(100005, "导入的文件数据为空"),

NO_SELECTED_CONFIG(100006, "没有选择任何配制"),


;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ const I18N_CONF = {
delSelectedAlertTitle: 'Delete config',
delSelectedAlertContent: 'please select the configuration to delete',
delSuccessMsg: 'delete successful',
cloneEditableTitle: 'Modify Data Id and Group (optional)',
},
NewConfig: {
newListingMain: 'Create Configuration',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ const I18N_CONF = {
delSelectedAlertTitle: '配置删除',
delSelectedAlertContent: '请选择要删除的配置',
delSuccessMsg: '删除成功',
cloneEditableTitle: '修改 Data Id 和 Group (可选操作)',
},
NewConfig: {
newListingMain: '新建配置',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import ShowCodeing from 'components/ShowCodeing';
import DeleteDialog from 'components/DeleteDialog';
import DashboardCard from './DashboardCard';
import { getParams, setParams, request, aliwareIntl } from '@/globalLib';
import axios from 'axios';

import './index.scss';
import { LANGUAGE_KEY } from '../../../constants';
Expand Down Expand Up @@ -689,10 +690,9 @@ class ConfigurationManagement extends React.Component {
}

exportData() {
let url =
`v1/cs/configs?export=true&group=${this.group}&tenant=${getParams('namespace')}&appName=${
this.appName
}&ids=&dataId=` + this.dataId;
let url = `v1/cs/configs?export=true&group=${this.group}&tenant=${getParams(
'namespace'
)}&appName=${this.appName}&ids=&dataId=${this.dataId}`;
window.location.href = url;
}

Expand Down Expand Up @@ -783,19 +783,54 @@ class ConfigurationManagement extends React.Component {
}
let namespaces = data.data;
let namespaceSelectData = [];
let namespaceSelecItemRender = item => {
if (item.isCurrent) {
return <span style={{ color: '#00AA00', 'font-weight': 'bold' }}>{item.label}</span>;
} else {
return <span>{item.label}</span>;
}
};
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);
let dataItem = {};
dataItem.isCurrent = false;
if (self.state.nownamespace_id === item.namespace) {
dataItem.isCurrent = true;
}
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);
});

let editableTableData = [];
let configsTableSelectedDeepCopyed = new Map();
configsTableSelected.forEach((value, key, map) => {
let dataItem = {};
dataItem.id = key;
dataItem.dataId = value.dataId;
dataItem.group = value.group;
editableTableData.push(dataItem);
configsTableSelectedDeepCopyed.set(key, JSON.parse(JSON.stringify(value)));
});
let editableTableOnBlur = (record, type, e) => {
if (type === 1) {
configsTableSelectedDeepCopyed.get(record.id).dataId = e.target.value;
} else {
configsTableSelectedDeepCopyed.get(record.id).group = e.target.value;
}
};

let renderEditableTableCellDataId = (value, index, record) => (
<Input defaultValue={value} onBlur={editableTableOnBlur.bind(this, record, 1)} />
);
let renderEditableTableCellGroup = (value, index, record) => (
<Input defaultValue={value} onBlur={editableTableOnBlur.bind(this, record, 2)} />
);

const cloneConfirm = Dialog.confirm({
title: locale.cloningConfiguration,
footer: false,
Expand All @@ -822,6 +857,7 @@ class ConfigurationManagement extends React.Component {
showSearch
hasClear={false}
mode="single"
itemRender={namespaceSelecItemRender}
dataSource={namespaceSelectData}
onChange={(value, actionType, item) => {
if (value) {
Expand Down Expand Up @@ -866,7 +902,7 @@ class ConfigurationManagement extends React.Component {
}}
/>
</div>
<div>
<div style={{ marginBottom: 10 }}>
<Button
type={'primary'}
style={{ marginRight: 10 }}
Expand All @@ -878,13 +914,21 @@ class ConfigurationManagement extends React.Component {
document.getElementById('cloneTargetSpaceSelectErr').style.display = 'none';
}
let idsStr = '';
configsTableSelected.forEach((value, key, map) => {
idsStr = `${idsStr + key},`;
let clonePostData = [];
configsTableSelectedDeepCopyed.forEach((value, key, map) => {
let postDataItem = {};
postDataItem.cfgId = key;
postDataItem.dataId = value.dataId;
postDataItem.group = value.group;
clonePostData.push(postDataItem);
});
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}`,
url: `v1/cs/configs?clone=true&tenant=${cloneTargetSpace}&policy=${sameConfigPolicy}&namespaceId=`,
method: 'post',
data: JSON.stringify(clonePostData),
contentType: 'application/json',
beforeSend() {
self.openLoading();
},
Expand All @@ -908,6 +952,25 @@ class ConfigurationManagement extends React.Component {
{locale.startCloning}
</Button>
</div>
<div style={{ marginBottom: 10 }}>
<span style={{ color: '#00AA00', 'font-weight': 'bold' }}>
{locale.cloneEditableTitle}
</span>
</div>
<div>
<Table dataSource={editableTableData}>
<Table.Column
title="Data Id"
dataIndex="dataId"
cell={renderEditableTableCellDataId}
/>
<Table.Column
title="Group"
dataIndex="group"
cell={renderEditableTableCellGroup}
/>
</Table>
</div>
</div>
),
});
Expand Down Expand Up @@ -1089,7 +1152,9 @@ class ConfigurationManagement extends React.Component {
rowSelection.selectedRowKeys = ids;
this.setState({ rowSelection });
configsTableSelected.clear();
records.forEach(item => configsTableSelected.set(item.id, item));
records.forEach((record, i) => {
configsTableSelected.set(record.id, record);
});
}

render() {
Expand Down
2 changes: 1 addition & 1 deletion console/src/main/resources/static/css/main.css

Large diffs are not rendered by default.

Loading