mirror of
https://github.com/goharbor/harbor.git
synced 2024-12-20 15:48:26 +01:00
Fix replication frontend issues
Signed-off-by: FangyuanCheng <fangyuanc@vmware.com>
This commit is contained in:
parent
7729bca23b
commit
609f6cbda2
@ -257,10 +257,7 @@ export class CreateEditEndpointComponent
|
||||
},
|
||||
error => {
|
||||
this.onGoing = false;
|
||||
let errorMessageKey = this.handleErrorMessageKey(error.status);
|
||||
this.translateService.get(errorMessageKey).subscribe(res => {
|
||||
this.inlineAlert.showInlineError(res);
|
||||
});
|
||||
this.inlineAlert.showInlineError(error);
|
||||
this.forceRefreshView(2000);
|
||||
}
|
||||
);
|
||||
@ -302,27 +299,13 @@ export class CreateEditEndpointComponent
|
||||
this.forceRefreshView(2000);
|
||||
},
|
||||
error => {
|
||||
let errorMessageKey = this.handleErrorMessageKey(error.status);
|
||||
this.translateService.get(errorMessageKey).subscribe(res => {
|
||||
this.inlineAlert.showInlineError(res);
|
||||
});
|
||||
this.inlineAlert.showInlineError(error);
|
||||
this.onGoing = false;
|
||||
this.forceRefreshView(2000);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
handleErrorMessageKey(status: number): string {
|
||||
switch (status) {
|
||||
case 409:
|
||||
return "DESTINATION.CONFLICT_NAME";
|
||||
case 400:
|
||||
return "DESTINATION.INVALID_NAME";
|
||||
default:
|
||||
return "UNKNOWN_ERROR";
|
||||
}
|
||||
}
|
||||
|
||||
onCancel() {
|
||||
let changes: { [key: string]: any } = this.getChanges();
|
||||
if (!isEmptyObject(changes)) {
|
||||
|
@ -133,12 +133,18 @@
|
||||
<label for="ruleDeletion" class="clr-control-label">{{'REPLICATION.DELETE_REMOTE_IMAGES' | translate}}</label>
|
||||
</clr-checkbox-wrapper>
|
||||
</div>
|
||||
<div class="clr-form-control rule-width">
|
||||
<div class="rule-width">
|
||||
<clr-checkbox-wrapper>
|
||||
<input type="checkbox" clrCheckbox [checked]="true" id="enablePolicy" formControlName="enabled" class="clr-checkbox">
|
||||
<label for="enablePolicy" class="clr-control-label">{{'REPLICATION.ENABLED' | translate}}</label>
|
||||
</clr-checkbox-wrapper>
|
||||
</div>
|
||||
<div class="rule-width">
|
||||
<clr-checkbox-wrapper>
|
||||
<input type="checkbox" clrCheckbox [checked]="true" id="overridePolicy" formControlName="override" class="clr-checkbox">
|
||||
<label for="overridePolicy" class="clr-control-label">{{'REPLICATION.OVERRIDE' | translate}}</label>
|
||||
</clr-checkbox-wrapper>
|
||||
</div>
|
||||
</div>
|
||||
<div class="loading-center">
|
||||
<span class="spinner spinner-inline" [hidden]="inProgress === false"></span>
|
||||
|
@ -54,7 +54,8 @@ describe("CreateEditRuleComponent (inline template)", () => {
|
||||
},
|
||||
filters: [],
|
||||
deletion: false,
|
||||
enabled: true
|
||||
enabled: true,
|
||||
override: true
|
||||
}
|
||||
];
|
||||
let mockJobs: ReplicationJobItem[] = [
|
||||
@ -166,7 +167,8 @@ describe("CreateEditRuleComponent (inline template)", () => {
|
||||
},
|
||||
filters: [],
|
||||
deletion: false,
|
||||
enabled: true
|
||||
enabled: true,
|
||||
override: true
|
||||
};
|
||||
|
||||
let mockRegistryInfo = {
|
||||
|
@ -191,7 +191,8 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
||||
}),
|
||||
filters: this.fb.array([]),
|
||||
deletion: false,
|
||||
enabled: true
|
||||
enabled: true,
|
||||
override: true
|
||||
});
|
||||
}
|
||||
|
||||
@ -218,7 +219,8 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
},
|
||||
deletion: false,
|
||||
enabled: true
|
||||
enabled: true,
|
||||
override: true
|
||||
});
|
||||
this.isPushMode = true;
|
||||
}
|
||||
@ -236,6 +238,7 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
||||
} else {
|
||||
this.isPushMode = true;
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
this.ruleForm.reset({
|
||||
name: rule.name,
|
||||
@ -246,7 +249,8 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
||||
dest_registry: rule.dest_registry,
|
||||
trigger: rule.trigger,
|
||||
deletion: rule.deletion,
|
||||
enabled: rule.enabled
|
||||
enabled: rule.enabled,
|
||||
override: rule.override
|
||||
});
|
||||
// reset the filter list.
|
||||
let filters = [];
|
||||
@ -260,7 +264,6 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!findTag) {
|
||||
filters.push({ type: this.supportedFilters[i].type, value: "" });
|
||||
}
|
||||
|
@ -118,7 +118,6 @@ export class EndpointComponent implements OnInit, OnDestroy {
|
||||
this.endpointService.getEndpoints(this.targetName)
|
||||
.subscribe(targets => {
|
||||
this.targets = targets || [];
|
||||
this.forceRefreshView(1000);
|
||||
this.loading = false;
|
||||
}, error => {
|
||||
this.errorHandler.error(error);
|
||||
|
@ -8,10 +8,10 @@
|
||||
</clr-dg-action-bar>
|
||||
<clr-dg-column>{{'REPLICATION.NAME' | translate}}</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'status'" class="status-width">{{'REPLICATION.STATUS' | translate}}</clr-dg-column>
|
||||
<clr-dg-column class="min-width">{{'REPLICATION.SRC_NAMESPACE' | translate}}</clr-dg-column>
|
||||
<clr-dg-column>{{'REPLICATION.REPLICATION_MODE' | translate}}</clr-dg-column>
|
||||
<clr-dg-column class="min-width">{{'REPLICATION.SRC_REGISTRY' | translate}}</clr-dg-column>
|
||||
<clr-dg-column class="min-width">{{'REPLICATION.DESTINATION_NAMESPACE' | translate}}</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'trigger'">{{'REPLICATION.REPLICATION_TRIGGER' | translate}}</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'override'" class="status-width">{{'REPLICATION.OVERRIDE' | translate}}</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'description'">{{'REPLICATION.DESCRIPTION' | translate}}</clr-dg-column>
|
||||
<clr-dg-placeholder>{{'REPLICATION.PLACEHOLDER' | translate }}</clr-dg-placeholder>
|
||||
<clr-dg-row *clrDgItems="let p of changedRules; let i=index" [clrDgItem]="p" [style.backgroundColor]="(projectScope && withReplicationJob && selectedId === p.id) ? '#eee' : ''">
|
||||
@ -28,7 +28,7 @@
|
||||
</div>
|
||||
</clr-dg-cell>
|
||||
<clr-dg-cell class="min-width">
|
||||
{{p.src_registry ? p.src_registry.name : ''}} : {{p.src_namespaces?.length>0 ? p.src_namespaces[0]: ''}}
|
||||
{{p.src_registry ? p.src_registry.name : ''}}
|
||||
<clr-tooltip>
|
||||
<clr-icon *ngIf="p.src_namespaces && p.src_namespaces.length > 1" clrTooltipTrigger shape="ellipsis-horizontal" size="18"></clr-icon>
|
||||
<clr-tooltip-content clrPosition="top-right" clrSize="md" *clrIfOpen>
|
||||
@ -36,13 +36,14 @@
|
||||
</clr-tooltip-content>
|
||||
</clr-tooltip>
|
||||
</clr-dg-cell>
|
||||
<clr-dg-cell>
|
||||
{{p.src_registry && p.src_registry.id > 0 ? 'pull-based' : 'push-based'}}
|
||||
</clr-dg-cell>
|
||||
<clr-dg-cell class="min-width">
|
||||
{{p.dest_registry ? p.dest_registry.name : ''}} : {{p.dest_namespace? p.dest_namespace: '-'}}
|
||||
</clr-dg-cell>
|
||||
<clr-dg-cell>{{p.trigger ? p.trigger.type : ''}}</clr-dg-cell>
|
||||
<clr-dg-cell [ngSwitch]="p.override">
|
||||
<clr-icon shape="check-circle" *ngSwitchCase="true" size="20" class="color-green"></clr-icon>
|
||||
<clr-icon shape="times-circle" *ngSwitchCase="false" size="16" class="icon-style"></clr-icon>
|
||||
</clr-dg-cell>
|
||||
<clr-dg-cell>
|
||||
{{p.description ? trancatedDescription(p.description) : '-'}}
|
||||
<clr-tooltip>
|
||||
|
@ -11,3 +11,7 @@
|
||||
.status-width {
|
||||
width: 105px;
|
||||
}
|
||||
|
||||
.icon-style {
|
||||
color: #C92100;
|
||||
}
|
||||
|
@ -29,7 +29,8 @@ describe('ListReplicationRuleComponent (inline template)', () => {
|
||||
"deletion": false,
|
||||
"src_namespaces": ["name1", "name2"],
|
||||
"src_registry": {id: 3},
|
||||
"enabled": true
|
||||
"enabled": true,
|
||||
"override": true
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
@ -41,7 +42,8 @@ describe('ListReplicationRuleComponent (inline template)', () => {
|
||||
"deletion": false,
|
||||
"src_namespaces": ["name1", "name2"],
|
||||
"dest_registry": {id: 3},
|
||||
"enabled": true
|
||||
"enabled": true,
|
||||
"override": true
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -49,17 +49,25 @@
|
||||
<div class="flex-block">
|
||||
<section class="execution-detail-label">
|
||||
<section class="detail-row">
|
||||
<span class="label label-purple detail-span">{{'REPLICATION.SUCCESS'| translate}}</span>
|
||||
<div class="num-success common-style"></div>
|
||||
<label class="detail-span">{{'REPLICATION.SUCCESS'| translate}}</label>
|
||||
<div class="execution-details">{{successNum}}</div>
|
||||
</section>
|
||||
<section class="detail-row">
|
||||
<span class="label label-red detail-span">{{'REPLICATION.FAILURE'| translate}}</span>
|
||||
<div class="num-failed common-style"></div>
|
||||
<label class="detail-span">{{'REPLICATION.FAILURE'| translate}}</label>
|
||||
<div class="execution-details">{{failedNum}}</div>
|
||||
</section>
|
||||
<section class="detail-row">
|
||||
<span class="label label-light-blue detail-span">{{'REPLICATION.IN_PROGRESS'| translate}}</span>
|
||||
<div class="num-progress common-style"></div>
|
||||
<label class="detail-span">{{'REPLICATION.IN_PROGRESS'| translate}}</label>
|
||||
<div class="execution-details">{{progressNum}}</div>
|
||||
</section>
|
||||
<section class="detail-row">
|
||||
<div class="num-stopped common-style"></div>
|
||||
<label class="detail-span">{{'REPLICATION.STOPPED'| translate}}</label>
|
||||
<div class="execution-details">{{stoppedNum}}</div>
|
||||
</section>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -41,9 +41,27 @@
|
||||
text-align: left;
|
||||
.detail-row {
|
||||
display: flex;
|
||||
height: 27px;
|
||||
.common-style {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
.num-success {
|
||||
background-color: #308700;
|
||||
}
|
||||
.num-failed {
|
||||
background-color: #C92101;
|
||||
}
|
||||
.num-progress {
|
||||
background-color: #1C5898;
|
||||
}
|
||||
.num-stopped {
|
||||
background-color: #A1A1A1;
|
||||
}
|
||||
.detail-span {
|
||||
flex:0 0 100px;
|
||||
margin-top: 10px;
|
||||
margin: 10px 0 0 10px;
|
||||
}
|
||||
.execution-details {
|
||||
width: 200px;
|
||||
|
@ -1,18 +1,20 @@
|
||||
import { Component, OnInit, Input } from '@angular/core';
|
||||
import { Component, OnInit, Input, OnDestroy } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { ReplicationService } from "../../service/replication.service";
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { finalize } from "rxjs/operators";
|
||||
import { Subscription, timer } from "rxjs";
|
||||
import { ErrorHandler } from "../../error-handler/error-handler";
|
||||
import { ReplicationJob, ReplicationTasks, Comparator, ReplicationJobItem, State } from "../../service/interface";
|
||||
import { CustomComparator, DEFAULT_PAGE_SIZE, calculatePage, doFiltering, doSorting } from "../../utils";
|
||||
import { RequestQueryParams } from "../../service/RequestQueryParams";
|
||||
const taskStatus = 'InProgress';
|
||||
@Component({
|
||||
selector: 'replication-tasks',
|
||||
templateUrl: './replication-tasks.component.html',
|
||||
styleUrls: ['./replication-tasks.component.scss']
|
||||
})
|
||||
export class ReplicationTasksComponent implements OnInit {
|
||||
export class ReplicationTasksComponent implements OnInit, OnDestroy {
|
||||
isOpenFilterTag: boolean;
|
||||
selectedRow: [];
|
||||
currentPage: number = 1;
|
||||
@ -28,6 +30,7 @@ export class ReplicationTasksComponent implements OnInit {
|
||||
tasksCopy: ReplicationTasks[] = [];
|
||||
stopOnGoing: boolean;
|
||||
executions: ReplicationJobItem[];
|
||||
timerDelay: Subscription;
|
||||
@Input() executionId: string;
|
||||
startTimeComparator: Comparator<ReplicationJob> = new CustomComparator<
|
||||
ReplicationJob
|
||||
@ -84,6 +87,10 @@ export class ReplicationTasksComponent implements OnInit {
|
||||
return this.executions && this.executions['in_progress'];
|
||||
}
|
||||
|
||||
public get stoppedNum(): string {
|
||||
return this.executions && this.executions['stopped'];
|
||||
}
|
||||
|
||||
stopJob() {
|
||||
this.stopOnGoing = true;
|
||||
this.replicationService.stopJobs(this.executionId)
|
||||
@ -103,8 +110,13 @@ export class ReplicationTasksComponent implements OnInit {
|
||||
return this.replicationService.getJobBaseUrl() + "/executions/" + this.executionId + "/tasks/" + taskId + "/log";
|
||||
}
|
||||
|
||||
clrLoadTasks(state: State): void {
|
||||
ngOnDestroy() {
|
||||
if (this.timerDelay) {
|
||||
this.timerDelay.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
clrLoadTasks(state: State): void {
|
||||
if (!state || !state.page) {
|
||||
return;
|
||||
}
|
||||
@ -128,6 +140,24 @@ export class ReplicationTasksComponent implements OnInit {
|
||||
this.totalCount = res.length;
|
||||
this.tasks = res; // Keep the data
|
||||
this.taskItem = this.tasks.filter(tasks => tasks.resource_type !== "");
|
||||
if (!this.timerDelay) {
|
||||
this.timerDelay = timer(10000, 10000).subscribe(() => {
|
||||
let count: number = 0;
|
||||
this.tasks.forEach(tasks => {
|
||||
if (
|
||||
tasks.status === taskStatus
|
||||
) {
|
||||
count++;
|
||||
}
|
||||
});
|
||||
if (count > 0) {
|
||||
this.clrLoadTasks(this.currentState);
|
||||
} else {
|
||||
this.timerDelay.unsubscribe();
|
||||
this.timerDelay = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
this.taskItem = doFiltering<ReplicationTasks>(this.taskItem, state);
|
||||
|
||||
this.taskItem = doSorting<ReplicationTasks>(this.taskItem, state);
|
||||
|
@ -55,6 +55,7 @@
|
||||
<clr-dg-column [clrDgSortBy]="creationTimeComparator">{{'REPLICATION.CREATION_TIME' | translate}}</clr-dg-column>
|
||||
<clr-dg-column>{{'REPLICATION.DURATION' | translate}}</clr-dg-column>
|
||||
<clr-dg-column>{{'REPLICATION.SUCCESS_RATE' | translate}}</clr-dg-column>
|
||||
<clr-dg-column>{{'REPLICATION.TOTAL' | translate}}</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'status'">{{'REPLICATION.STATUS' | translate}}</clr-dg-column>
|
||||
<clr-dg-placeholder>{{'REPLICATION.JOB_PLACEHOLDER' | translate }}</clr-dg-placeholder>
|
||||
<clr-dg-row *ngFor="let j of jobs" [clrDgItem]="j">
|
||||
@ -67,6 +68,7 @@
|
||||
<clr-dg-cell>
|
||||
{{(j.succeed > 0 ? j.succeed / j.total : 0) | percent }}
|
||||
</clr-dg-cell>
|
||||
<clr-dg-cell>{{j.total}}</clr-dg-cell>
|
||||
<clr-dg-cell>
|
||||
{{j.status}}
|
||||
<clr-tooltip>
|
||||
|
@ -39,7 +39,8 @@ describe('Replication Component (inline template)', () => {
|
||||
"deletion": false,
|
||||
"src_registry": {id: 3},
|
||||
"src_namespaces": ["name1"],
|
||||
"enabled": true
|
||||
"enabled": true,
|
||||
"override": true
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
@ -51,7 +52,8 @@ describe('Replication Component (inline template)', () => {
|
||||
"deletion": false,
|
||||
"dest_registry": {id: 5},
|
||||
"src_namespaces": ["name1"],
|
||||
"enabled": true
|
||||
"enabled": true,
|
||||
"override": true
|
||||
}
|
||||
];
|
||||
|
||||
|
@ -114,6 +114,7 @@ export interface ReplicationRule extends Base {
|
||||
src_namespaces: string [];
|
||||
dest_namespace?: string;
|
||||
enabled: boolean;
|
||||
override: boolean;
|
||||
}
|
||||
|
||||
export class Filter {
|
||||
|
@ -23,6 +23,11 @@ export const errorHandler = function (error: any): string {
|
||||
if (!error) {
|
||||
return "UNKNOWN_ERROR";
|
||||
}
|
||||
|
||||
if (error && error._body) {
|
||||
return error._body;
|
||||
}
|
||||
|
||||
if (!(error.statusCode || error.status)) {
|
||||
// treat as string message
|
||||
return '' + error;
|
||||
|
@ -340,6 +340,8 @@
|
||||
"OF": "of"
|
||||
},
|
||||
"REPLICATION": {
|
||||
"TOTAL": "Total",
|
||||
"OVERRIDE": "Override",
|
||||
"OPERATION": "Operation",
|
||||
"CURRENT": "current",
|
||||
"FILTER_PLACEHOLDER": "Filter Tasks",
|
||||
@ -386,7 +388,7 @@
|
||||
"ENABLE": "Enable",
|
||||
"DISABLE": "Disable",
|
||||
"REPLICATION_MODE": "Replication Mode",
|
||||
"SRC_NAMESPACE": "Source registry:Namespace",
|
||||
"SRC_REGISTRY": "Source registry",
|
||||
"DESTINATION_NAMESPACE": "Destination registry:Namespace",
|
||||
"LAST_REPLICATION":"Last Replication",
|
||||
"DESTINATION_NAME_IS_REQUIRED": "Endpoint name is required.",
|
||||
@ -408,7 +410,7 @@
|
||||
"RUNNING": "Running",
|
||||
"ERROR": "Error",
|
||||
"RETRYING": "Retrying",
|
||||
"STOPPED": "Stopped",
|
||||
"STOPPED": "STOPPED",
|
||||
"FINISHED": "Finished",
|
||||
"CANCELED": "Canceled",
|
||||
"SIMPLE": "Simple",
|
||||
|
@ -339,6 +339,8 @@
|
||||
"OF": "of"
|
||||
},
|
||||
"REPLICATION": {
|
||||
"TOTAL": "Total",
|
||||
"OVERRIDE": "Anular",
|
||||
"CURRENT": "current",
|
||||
"FILTER_PLACEHOLDER": "Filter Tasks",
|
||||
"STOP_TITLE": "Confirme Stop Executions",
|
||||
@ -386,7 +388,7 @@
|
||||
"ENABLE": "Activar",
|
||||
"DISABLE": "Desactivar",
|
||||
"REPLICATION_MODE": "Replication Mode",
|
||||
"SRC_NAMESPACE": "Source registry:Namespace",
|
||||
"SRC_REGISTRY": "Source registry",
|
||||
"DESTINATION_NAMESPACE": "Destination registry:Namespace",
|
||||
"LAST_REPLICATION":"Last Replication",
|
||||
"DESTINATION_NAME_IS_REQUIRED": "El nombre del endpoint es obligatorio.",
|
||||
|
@ -324,6 +324,8 @@
|
||||
"OF": "de"
|
||||
},
|
||||
"REPLICATION": {
|
||||
"TOTAL": "Total",
|
||||
"OVERRIDE": "Passer outre",
|
||||
"CURRENT": "current",
|
||||
"FILTER_PLACEHOLDER": "Filter Tasks",
|
||||
"STOP_TITLE": "Confirmer arrêter les exécutions",
|
||||
@ -368,7 +370,7 @@
|
||||
"ENABLE": "Activer",
|
||||
"DISABLE": "Désactiver",
|
||||
"REPLICATION_MODE": "Replication Mode",
|
||||
"SRC_NAMESPACE": "Source registry:Namespace",
|
||||
"SRC_REGISTRY": "Source registry",
|
||||
"DESTINATION_NAMESPACE": "Destination registry:Namespace",
|
||||
"LAST_REPLICATION":"Last Replication",
|
||||
"DESTINATION_NAME_IS_REQUIRED": "Le nom du Point Final est obligatoire.",
|
||||
@ -390,7 +392,7 @@
|
||||
"RUNNING": "En fonctionnement",
|
||||
"ERROR": "Erreur",
|
||||
"RETRYING": "En train de réessayer",
|
||||
"STOPPED": "Stoppé",
|
||||
"STOPPED": "STOPPED",
|
||||
"FINISHED": "Terminé",
|
||||
"CANCELED": "Annulé",
|
||||
"SIMPLE": "Simple",
|
||||
|
@ -338,6 +338,8 @@
|
||||
"OF": "de"
|
||||
},
|
||||
"REPLICATION": {
|
||||
"TOTAL": "Total",
|
||||
"OVERRIDE": "Substituir",
|
||||
"CURRENT": "current",
|
||||
"FILTER_PLACEHOLDER": "Filter Tasks",
|
||||
"STOP_TITLE": "Confirme as execuções de parada",
|
||||
@ -385,7 +387,7 @@
|
||||
"ENABLE": "Habilitar",
|
||||
"DISABLE": "Desabilitar",
|
||||
"REPLICATION_MODE": "Replication Mode",
|
||||
"SRC_NAMESPACE": "Source registry:Namespace",
|
||||
"SRC_REGISTRY": "Source registry",
|
||||
"DESTINATION_NAMESPACE": "Destination registry:Namespace",
|
||||
"LAST_REPLICATION":"Last Replication",
|
||||
"DESTINATION_NAME_IS_REQUIRED": "Nome do Endpoint é obrigatório.",
|
||||
@ -408,7 +410,7 @@
|
||||
"RUNNING": "Executando",
|
||||
"ERROR": "Erro",
|
||||
"RETRYING": "Tentando novamente",
|
||||
"STOPPED": "Parada",
|
||||
"STOPPED": "STOPPED",
|
||||
"FINISHED": "Finalizada",
|
||||
"CANCELED": "Cancelada",
|
||||
"SIMPLE": "Simples",
|
||||
|
@ -339,6 +339,8 @@
|
||||
"OF": "共计"
|
||||
},
|
||||
"REPLICATION": {
|
||||
"TOTAL": "总数",
|
||||
"OVERRIDE": "覆盖",
|
||||
"CURRENT": "当前仓库",
|
||||
"FILTER_PLACEHOLDER": "过滤任务",
|
||||
"STOP_TITLE": "确认停止任务",
|
||||
@ -386,7 +388,7 @@
|
||||
"ENABLE": "启用",
|
||||
"DISABLE": "停用",
|
||||
"REPLICATION_MODE": "复制模式",
|
||||
"SRC_NAMESPACE": "源仓库:命名空间",
|
||||
"SRC_REGISTRY": "源仓库",
|
||||
"DESTINATION_NAMESPACE": "目标仓库:命名空间",
|
||||
"LAST_REPLICATION":"最后一次复制",
|
||||
"DESTINATION_NAME_IS_REQUIRED": "目标名称为必填项。",
|
||||
|
Loading…
Reference in New Issue
Block a user