1 parent
d616e6b1a8
commit
6a06a12455
14 files changed
+388
-20
No files matched your search
@@ -16,7 +16,7 @@ import DangerConfirmDialog from "@/components/editor/DangerConfirmDialog.vue";
|
||||
import EditorSearchPanel from "@/components/editor/EditorSearchPanel.vue";
|
||||
import NacosConfigDiffDialog from "@/components/nacos/NacosConfigDiffDialog.vue";
|
||||
import NacosConfigHistoryDialog from "@/components/nacos/NacosConfigHistoryDialog.vue";
|
||||
import NacosConfigBatchDialog, { type NacosBatchDialogMode, type NacosConfigTransferTarget } from "@/components/nacos/NacosConfigBatchDialog.vue";
|
||||
import NacosConfigBatchDialog, { type NacosBatchDialogMode, type NacosConfigTransferDialogPayload, type NacosConfigTransferTarget } from "@/components/nacos/NacosConfigBatchDialog.vue";
|
||||
import NacosContentSearchDialog from "@/components/nacos/NacosContentSearchDialog.vue";
|
||||
import { useToast } from "@/composables/useToast";
|
||||
import { useNacosConfigListColumnResize, type ToggleableNacosConfigListColumnKey } from "@/composables/useNacosConfigListColumnResize";
|
||||
@@ -67,7 +67,6 @@ import type {
|
||||
NacosConnectionInfo,
|
||||
NacosContentMatch,
|
||||
NacosContentSearchResult,
|
||||
NacosConflictPolicy,
|
||||
NacosInstanceInfo,
|
||||
NacosInstancePatch,
|
||||
NacosInstanceRef,
|
||||
@@ -435,6 +434,8 @@ function selectedKeys(): NacosConfigKey[] {
|
||||
});
|
||||
}
|
||||
|
||||
const selectedConfigTransferKeys = computed(() => selectedKeys());
|
||||
|
||||
function isBatchDeleteSnapshotInScope(snapshot: NacosBatchDeleteSnapshot) {
|
||||
return snapshot.connectionId === props.connectionId && snapshot.namespace === namespace.value;
|
||||
}
|
||||
@@ -1245,7 +1246,7 @@ async function exportConfigArchive(scope: NacosConfigSelectionScope) {
|
||||
|
||||
const batchTransferRequest = shallowRef<NacosConfigTransferRequest | null>(null);
|
||||
|
||||
async function previewBatch(payload: { scope: NacosConfigSelectionScope; targetConnectionId: string; targetNamespace: string; targetGroup: string; policy: NacosConflictPolicy }) {
|
||||
async function previewBatch(payload: NacosConfigTransferDialogPayload) {
|
||||
batchLoading.value = true;
|
||||
batchError.value = "";
|
||||
batchPreview.value = null;
|
||||
@@ -1262,6 +1263,7 @@ async function previewBatch(payload: { scope: NacosConfigSelectionScope; targetC
|
||||
source: buildConfigSelector(payload.scope),
|
||||
targetNamespace: payload.targetNamespace,
|
||||
targetGroup: payload.targetGroup || undefined,
|
||||
dataIdMappings: payload.dataIdMappings,
|
||||
conflictPolicy: payload.policy,
|
||||
};
|
||||
batchTransferRequest.value = req;
|
||||
@@ -1274,7 +1276,7 @@ async function previewBatch(payload: { scope: NacosConfigSelectionScope; targetC
|
||||
}
|
||||
}
|
||||
|
||||
async function applyBatch(payload: { scope: NacosConfigSelectionScope; targetConnectionId: string; targetNamespace: string; targetGroup: string; policy: NacosConflictPolicy }) {
|
||||
async function applyBatch(payload: NacosConfigTransferDialogPayload) {
|
||||
if (batchLoading.value || batchReport.value || !batchPreview.value) return;
|
||||
if (payload.policy === "OVERWRITE" && !window.confirm(t("nacos.overwriteConfirm"))) return;
|
||||
const targetConnectionId = batchMode.value === "import" ? props.connectionId : payload.targetConnectionId;
|
||||
@@ -3030,6 +3032,7 @@ onBeforeUnmount(() => {
|
||||
:mode="batchMode"
|
||||
:loading="batchLoading"
|
||||
:selected-count="selectedConfigCount"
|
||||
:selected-keys="selectedConfigTransferKeys"
|
||||
:filtered-count="configTotal"
|
||||
:target-connections="batchTargetConnections"
|
||||
:target-connection-id="batchTargetConnectionId"
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useI18n } from "vue-i18n";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog";
|
||||
import type { NacosBatchPreview, NacosBatchReport, NacosConfigSelectionScope, NacosConflictPolicy, NacosNamespaceInfo } from "@/types/nacos";
|
||||
import type { NacosBatchPreview, NacosBatchReport, NacosConfigDataIdMapping, NacosConfigKey, NacosConfigSelectionScope, NacosConflictPolicy, NacosNamespaceInfo } from "@/types/nacos";
|
||||
import { nacosNamespaceIdentity } from "@/lib/nacos/nacosNamespaceVisibility";
|
||||
|
||||
export type NacosBatchDialogMode = "export" | "import" | "copy";
|
||||
@@ -15,11 +15,21 @@ export interface NacosConfigTransferTarget {
|
||||
label: string;
|
||||
}
|
||||
|
||||
export interface NacosConfigTransferDialogPayload {
|
||||
scope: NacosConfigSelectionScope;
|
||||
targetConnectionId: string;
|
||||
targetNamespace: string;
|
||||
targetGroup: string;
|
||||
dataIdMappings?: NacosConfigDataIdMapping[];
|
||||
policy: NacosConflictPolicy;
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
open: boolean;
|
||||
mode: NacosBatchDialogMode;
|
||||
loading: boolean;
|
||||
selectedCount: number;
|
||||
selectedKeys: NacosConfigKey[];
|
||||
filteredCount: number;
|
||||
targetConnections: NacosConfigTransferTarget[];
|
||||
targetConnectionId: string;
|
||||
@@ -37,8 +47,8 @@ const emit = defineEmits<{
|
||||
chooseFile: [];
|
||||
reset: [];
|
||||
targetConnectionChange: [connectionId: string];
|
||||
preview: [payload: { scope: NacosConfigSelectionScope; targetConnectionId: string; targetNamespace: string; targetGroup: string; policy: NacosConflictPolicy }];
|
||||
apply: [payload: { scope: NacosConfigSelectionScope; targetConnectionId: string; targetNamespace: string; targetGroup: string; policy: NacosConflictPolicy }];
|
||||
preview: [payload: NacosConfigTransferDialogPayload];
|
||||
apply: [payload: NacosConfigTransferDialogPayload];
|
||||
export: [scope: NacosConfigSelectionScope];
|
||||
}>();
|
||||
|
||||
@@ -47,6 +57,7 @@ const scope = ref<NacosConfigSelectionScope>("selected");
|
||||
const policy = ref<NacosConflictPolicy>("ABORT");
|
||||
const targetNamespace = ref("");
|
||||
const targetGroup = ref("");
|
||||
const targetDataIdDrafts = ref<NacosConfigDataIdMapping[]>([]);
|
||||
|
||||
const titleKey = computed(() => `nacos.batch${props.mode[0].toUpperCase()}${props.mode.slice(1)}Title`);
|
||||
const descriptionKey = computed(() => `nacos.batch${props.mode[0].toUpperCase()}${props.mode.slice(1)}Description`);
|
||||
@@ -111,6 +122,32 @@ function resetTargetNamespace() {
|
||||
targetNamespace.value = targetNamespaces.value[0] ? JSON.stringify(targetNamespaces.value[0].namespace) : "";
|
||||
}
|
||||
|
||||
function resetTargetDataIdDrafts() {
|
||||
targetDataIdDrafts.value = props.selectedKeys.map((key) => ({
|
||||
sourceGroup: key.group,
|
||||
sourceDataId: key.dataId,
|
||||
targetDataId: "",
|
||||
}));
|
||||
}
|
||||
|
||||
function transferPayload(): NacosConfigTransferDialogPayload {
|
||||
const dataIdMappings =
|
||||
scope.value === "selected"
|
||||
? targetDataIdDrafts.value.flatMap((mapping) => {
|
||||
const targetDataId = mapping.targetDataId.trim();
|
||||
return targetDataId && targetDataId !== mapping.sourceDataId ? [{ ...mapping, targetDataId }] : [];
|
||||
})
|
||||
: [];
|
||||
return {
|
||||
scope: scope.value,
|
||||
targetConnectionId: props.targetConnectionId,
|
||||
targetNamespace: selectedTargetNamespace.value,
|
||||
targetGroup: targetGroup.value.trim(),
|
||||
...(dataIdMappings.length ? { dataIdMappings } : {}),
|
||||
policy: policy.value,
|
||||
};
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.open,
|
||||
(open) => {
|
||||
@@ -118,6 +155,7 @@ watch(
|
||||
scope.value = props.selectedCount ? "selected" : "filtered";
|
||||
policy.value = "ABORT";
|
||||
targetGroup.value = "";
|
||||
resetTargetDataIdDrafts();
|
||||
resetTargetNamespace();
|
||||
},
|
||||
{ immediate: true },
|
||||
@@ -206,7 +244,29 @@ watch(targetNamespaces, () => {
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<div class="text-sm font-medium">{{ t("nacos.targetGroup") }}</div>
|
||||
<input v-model="targetGroup" type="text" class="h-10 w-full rounded-md border border-input bg-background px-3 text-sm" :disabled="loading" :placeholder="t('nacos.targetGroupPlaceholder')" @change="emit('reset')" />
|
||||
<input v-model="targetGroup" data-testid="nacos-target-group" type="text" class="h-10 w-full rounded-md border border-input bg-background px-3 text-sm" :disabled="loading" :placeholder="t('nacos.targetGroupPlaceholder')" @change="emit('reset')" />
|
||||
</div>
|
||||
<div v-if="scope === 'selected' && targetDataIdDrafts.length" class="space-y-2">
|
||||
<div class="text-sm font-medium">{{ t("nacos.targetDataIds") }}</div>
|
||||
<p class="text-xs text-muted-foreground">{{ t("nacos.targetDataIdsHint") }}</p>
|
||||
<div class="max-h-52 space-y-2 overflow-auto rounded-md border p-2">
|
||||
<label v-for="(mapping, index) in targetDataIdDrafts" :key="`${mapping.sourceGroup}\u0000${mapping.sourceDataId}`" :for="`nacos-target-data-id-${index}`" class="grid gap-2 rounded-md bg-muted/30 p-2 text-xs sm:grid-cols-[minmax(0,1fr)_minmax(0,1fr)] sm:items-center">
|
||||
<span class="min-w-0">
|
||||
<span class="block truncate font-medium text-foreground" :title="mapping.sourceDataId">{{ mapping.sourceDataId }}</span>
|
||||
<span class="block truncate text-muted-foreground" :title="mapping.sourceGroup">{{ mapping.sourceGroup }}</span>
|
||||
</span>
|
||||
<input
|
||||
:id="`nacos-target-data-id-${index}`"
|
||||
v-model="mapping.targetDataId"
|
||||
data-testid="nacos-target-data-id"
|
||||
type="text"
|
||||
class="h-9 w-full rounded-md border border-input bg-background px-3 text-sm text-foreground"
|
||||
:disabled="loading"
|
||||
:placeholder="mapping.sourceDataId"
|
||||
@input="emit('reset')"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-xs text-muted-foreground">{{ t("nacos.copyKeepsSource") }}</p>
|
||||
</div>
|
||||
@@ -285,11 +345,11 @@ watch(targetNamespaces, () => {
|
||||
{{ t("nacos.exportZip") }}
|
||||
</Button>
|
||||
<template v-else>
|
||||
<Button v-if="!preview" :disabled="loading || !canContinue" @click="emit('preview', { scope, targetConnectionId, targetNamespace: selectedTargetNamespace, targetGroup: targetGroup.trim(), policy })">
|
||||
<Button v-if="!preview" :disabled="loading || !canContinue" @click="emit('preview', transferPayload())">
|
||||
<Loader2 v-if="loading" class="mr-2 h-4 w-4 animate-spin" />
|
||||
{{ t("nacos.preview") }}
|
||||
</Button>
|
||||
<Button v-else :variant="policy === 'OVERWRITE' ? 'destructive' : 'default'" :disabled="loading || hasPreviewBlockingErrors" @click="emit('apply', { scope, targetConnectionId, targetNamespace: selectedTargetNamespace, targetGroup: targetGroup.trim(), policy })">
|
||||
<Button v-else :variant="policy === 'OVERWRITE' ? 'destructive' : 'default'" :disabled="loading || hasPreviewBlockingErrors" @click="emit('apply', transferPayload())">
|
||||
<Loader2 v-if="loading" class="mr-2 h-4 w-4 animate-spin" />
|
||||
{{ t("nacos.apply") }}
|
||||
</Button>
|
||||
|
||||
+84
-3
@@ -4,7 +4,7 @@ import { createApp, defineComponent, h, nextTick, type App } from "vue";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import i18n from "@/i18n";
|
||||
import NacosConfigBatchDialog from "@/components/nacos/NacosConfigBatchDialog.vue";
|
||||
import type { NacosBatchReport } from "@/types/nacos";
|
||||
import type { NacosBatchReport, NacosConfigKey } from "@/types/nacos";
|
||||
|
||||
const mountedApps: App[] = [];
|
||||
|
||||
@@ -15,6 +15,7 @@ async function mountDialog(
|
||||
{ namespace: "remote-only", namespaceShowName: "Remote only" },
|
||||
],
|
||||
report: NacosBatchReport | null = null,
|
||||
selectedKeys: NacosConfigKey[] = [{ namespace: "shared", group: "DEFAULT_GROUP", dataId: "app.yaml" }],
|
||||
) {
|
||||
const onTargetConnectionChange = vi.fn();
|
||||
const onPreview = vi.fn();
|
||||
@@ -27,7 +28,8 @@ async function mountDialog(
|
||||
open: true,
|
||||
mode: "copy",
|
||||
loading: false,
|
||||
selectedCount: 1,
|
||||
selectedCount: selectedKeys.length,
|
||||
selectedKeys,
|
||||
filteredCount: 1,
|
||||
targetConnections: [
|
||||
{ id: "source", label: "Source" },
|
||||
@@ -80,7 +82,7 @@ describe("NacosConfigBatchDialog cross-connection sync", () => {
|
||||
|
||||
it("includes a trimmed target group override in the preview payload when provided", async () => {
|
||||
const { onPreview } = await mountDialog("remote");
|
||||
const groupInput = document.body.querySelector("input[type=text]") as HTMLInputElement;
|
||||
const groupInput = document.body.querySelector("[data-testid=nacos-target-group]") as HTMLInputElement;
|
||||
groupInput.value = " TARGET_GROUP ";
|
||||
groupInput.dispatchEvent(new Event("input"));
|
||||
await nextTick();
|
||||
@@ -98,6 +100,85 @@ describe("NacosConfigBatchDialog cross-connection sync", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("emits a trimmed target Data ID mapping for one selected config", async () => {
|
||||
const { onPreview } = await mountDialog("remote");
|
||||
const dataIdInput = document.body.querySelector("[data-testid=nacos-target-data-id]") as HTMLInputElement;
|
||||
dataIdInput.value = " app-prod.yaml ";
|
||||
dataIdInput.dispatchEvent(new Event("input"));
|
||||
await nextTick();
|
||||
|
||||
Array.from(document.body.querySelectorAll("button"))
|
||||
.find((button) => button.textContent?.includes("Preview"))
|
||||
?.click();
|
||||
await nextTick();
|
||||
|
||||
expect(onPreview).toHaveBeenCalledWith({
|
||||
scope: "selected",
|
||||
targetConnectionId: "remote",
|
||||
targetNamespace: "shared",
|
||||
targetGroup: "",
|
||||
dataIdMappings: [{ sourceGroup: "DEFAULT_GROUP", sourceDataId: "app.yaml", targetDataId: "app-prod.yaml" }],
|
||||
policy: "ABORT",
|
||||
});
|
||||
});
|
||||
|
||||
it("lets multiple selected configs independently retain or edit their target Data IDs", async () => {
|
||||
const selectedKeys = [
|
||||
{ namespace: "shared", group: "DEFAULT_GROUP", dataId: "app.yaml" },
|
||||
{ namespace: "shared", group: "WORKER_GROUP", dataId: "worker.yaml" },
|
||||
];
|
||||
const { onPreview } = await mountDialog("remote", undefined, null, selectedKeys);
|
||||
const dataIdInputs = Array.from(document.body.querySelectorAll("[data-testid=nacos-target-data-id]")) as HTMLInputElement[];
|
||||
expect(dataIdInputs).toHaveLength(2);
|
||||
dataIdInputs[1].value = "worker-prod.yaml";
|
||||
dataIdInputs[1].dispatchEvent(new Event("input"));
|
||||
await nextTick();
|
||||
|
||||
Array.from(document.body.querySelectorAll("button"))
|
||||
.find((button) => button.textContent?.includes("Preview"))
|
||||
?.click();
|
||||
await nextTick();
|
||||
|
||||
expect(onPreview).toHaveBeenCalledWith({
|
||||
scope: "selected",
|
||||
targetConnectionId: "remote",
|
||||
targetNamespace: "shared",
|
||||
targetGroup: "",
|
||||
dataIdMappings: [{ sourceGroup: "WORKER_GROUP", sourceDataId: "worker.yaml", targetDataId: "worker-prod.yaml" }],
|
||||
policy: "ABORT",
|
||||
});
|
||||
});
|
||||
|
||||
it("treats blank or unchanged target Data IDs as source-preserving defaults", async () => {
|
||||
const { onPreview } = await mountDialog("remote");
|
||||
const dataIdInput = document.body.querySelector("[data-testid=nacos-target-data-id]") as HTMLInputElement;
|
||||
dataIdInput.value = " app.yaml ";
|
||||
dataIdInput.dispatchEvent(new Event("input"));
|
||||
await nextTick();
|
||||
|
||||
Array.from(document.body.querySelectorAll("button"))
|
||||
.find((button) => button.textContent?.includes("Preview"))
|
||||
?.click();
|
||||
await nextTick();
|
||||
|
||||
expect(onPreview.mock.calls[0][0]).not.toHaveProperty("dataIdMappings");
|
||||
});
|
||||
|
||||
it("hides target Data ID editing and omits mappings for non-selected scopes", async () => {
|
||||
const { onPreview } = await mountDialog("remote");
|
||||
const filteredScope = document.body.querySelector("input[value=filtered]") as HTMLInputElement;
|
||||
filteredScope.click();
|
||||
await nextTick();
|
||||
|
||||
expect(document.body.querySelector("[data-testid=nacos-target-data-id]")).toBeNull();
|
||||
Array.from(document.body.querySelectorAll("button"))
|
||||
.find((button) => button.textContent?.includes("Preview"))
|
||||
?.click();
|
||||
await nextTick();
|
||||
|
||||
expect(onPreview.mock.calls[0][0]).not.toHaveProperty("dataIdMappings");
|
||||
});
|
||||
|
||||
it("excludes the source namespace only for same-connection sync and emits connection changes", async () => {
|
||||
const { onTargetConnectionChange } = await mountDialog("source");
|
||||
const selects = Array.from(document.body.querySelectorAll("select")) as HTMLSelectElement[];
|
||||
|
||||
@@ -8353,6 +8353,8 @@ export default {
|
||||
chooseTargetNamespace: "Choose another namespace",
|
||||
targetGroup: "Target group (optional)",
|
||||
targetGroupPlaceholder: "Same as source group",
|
||||
targetDataIds: "Target Data IDs (optional)",
|
||||
targetDataIdsHint: "Selected configs can be renamed individually. Leave a field blank to keep its source Data ID.",
|
||||
copyKeepsSource: "Sync uses one-way copy semantics. Source namespace configs stay unchanged.",
|
||||
conflictPolicy: "Conflict policy",
|
||||
policyABORT: "Abort on conflict",
|
||||
|
||||
@@ -6809,6 +6809,8 @@ export default withEnglishFallback({
|
||||
chooseTargetNamespace: "Seleccione otro namespace",
|
||||
targetGroup: "Group de destino (opcional)",
|
||||
targetGroupPlaceholder: "Igual que el group de origen",
|
||||
targetDataIds: "Data ID de destino (opcional)",
|
||||
targetDataIdsHint: "Las configuraciones seleccionadas se pueden renombrar individualmente. Deja un campo vacío para conservar el Data ID de origen.",
|
||||
copyKeepsSource: "La sincronización usa una copia unidireccional. Las configuraciones del namespace de origen no cambian.",
|
||||
conflictPolicy: "Política de conflictos",
|
||||
policyABORT: "Abortar al encontrar conflictos",
|
||||
|
||||
@@ -6810,6 +6810,8 @@ export default withEnglishFallback({
|
||||
chooseTargetNamespace: "Scegli un altro namespace",
|
||||
targetGroup: "Group di destinazione (facoltativo)",
|
||||
targetGroupPlaceholder: "Uguale al group di origine",
|
||||
targetDataIds: "Data ID di destinazione (facoltativi)",
|
||||
targetDataIdsHint: "Le configurazioni selezionate possono essere rinominate singolarmente. Lascia un campo vuoto per mantenere il Data ID di origine.",
|
||||
copyKeepsSource: "La sincronizzazione usa una copia unidirezionale. Le configurazioni del namespace di origine restano invariate.",
|
||||
conflictPolicy: "Strategia conflitti",
|
||||
policyABORT: "Interrompi in caso di conflitto",
|
||||
|
||||
@@ -6849,6 +6849,8 @@ export default withEnglishFallback({
|
||||
chooseTargetNamespace: "別の名前空間を選択",
|
||||
targetGroup: "宛先グループ(任意)",
|
||||
targetGroupPlaceholder: "元のグループと同じ",
|
||||
targetDataIds: "宛先 Data ID(任意)",
|
||||
targetDataIdsHint: "選択した設定ごとに Data ID を変更できます。空欄の場合は元の Data ID を保持します。",
|
||||
copyKeepsSource: "同期は一方向コピーです。元の名前空間の設定は変更されません。",
|
||||
conflictPolicy: "競合ポリシー",
|
||||
policyABORT: "競合時に中止",
|
||||
|
||||
@@ -7549,6 +7549,8 @@ export default withEnglishFallback({
|
||||
chooseTargetNamespace: "다른 네임스페이스 선택",
|
||||
targetGroup: "대상 그룹(선택 사항)",
|
||||
targetGroupPlaceholder: "원본 그룹과 동일",
|
||||
targetDataIds: "대상 Data ID(선택 사항)",
|
||||
targetDataIdsHint: "선택한 구성을 개별적으로 이름 변경할 수 있습니다. 비워 두면 원본 Data ID를 유지합니다.",
|
||||
copyKeepsSource: "동기화는 단방향 복사 의미를 사용합니다. 소스 네임스페이스 구성은 변경되지 않습니다.",
|
||||
conflictPolicy: "충돌 정책",
|
||||
policyABORT: "충돌 시 중단",
|
||||
|
||||
@@ -6811,6 +6811,8 @@ export default withEnglishFallback({
|
||||
chooseTargetNamespace: "Escolha outro namespace",
|
||||
targetGroup: "Group de destino (opcional)",
|
||||
targetGroupPlaceholder: "Igual ao group de origem",
|
||||
targetDataIds: "Data IDs de destino (opcional)",
|
||||
targetDataIdsHint: "As configurações selecionadas podem ser renomeadas individualmente. Deixe um campo vazio para manter o Data ID de origem.",
|
||||
copyKeepsSource: "A sincronização usa cópia unidirecional. As configurações do namespace de origem permanecem inalteradas.",
|
||||
conflictPolicy: "Política de conflitos",
|
||||
policyABORT: "Abortar ao encontrar conflito",
|
||||
|
||||
@@ -8334,6 +8334,8 @@ export default withEnglishFallback({
|
||||
chooseTargetNamespace: "请选择其他命名空间",
|
||||
targetGroup: "目标 Group(可选)",
|
||||
targetGroupPlaceholder: "与源 Group 相同",
|
||||
targetDataIds: "目标 Data ID(可选)",
|
||||
targetDataIdsHint: "可逐项修改已选配置的 Data ID;留空则保留源 Data ID。",
|
||||
copyKeepsSource: "同步采用单向复制语义,源命名空间中的配置保持不变。",
|
||||
conflictPolicy: "冲突策略",
|
||||
policyABORT: "遇冲突终止",
|
||||
|
||||
@@ -6119,6 +6119,8 @@ export default withEnglishFallback({
|
||||
chooseTargetNamespace: "請選擇其他命名空間",
|
||||
targetGroup: "目標 Group(選填)",
|
||||
targetGroupPlaceholder: "與來源 Group 相同",
|
||||
targetDataIds: "目標 Data ID(選填)",
|
||||
targetDataIdsHint: "可逐項修改已選設定的 Data ID;留空則保留來源 Data ID。",
|
||||
copyKeepsSource: "同步採用單向複製,來源命名空間中的設定保持不變。",
|
||||
conflictPolicy: "衝突策略",
|
||||
policyABORT: "遇到衝突時終止",
|
||||
|
||||
@@ -397,6 +397,12 @@ export interface NacosBatchReport {
|
||||
items: NacosBatchItemResult[];
|
||||
}
|
||||
|
||||
export interface NacosConfigDataIdMapping {
|
||||
sourceGroup: string;
|
||||
sourceDataId: string;
|
||||
targetDataId: string;
|
||||
}
|
||||
|
||||
export interface NacosConfigTransferRequest {
|
||||
operationId: string;
|
||||
sourceConnectionId: string;
|
||||
@@ -404,6 +410,7 @@ export interface NacosConfigTransferRequest {
|
||||
source: NacosConfigSelector;
|
||||
targetNamespace: string;
|
||||
targetGroup?: string;
|
||||
dataIdMappings?: NacosConfigDataIdMapping[];
|
||||
conflictPolicy: NacosConflictPolicy;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user