Merge pull request #1875 from wknet123/dev-revised

Fix UX issues.
This commit is contained in:
Steven Zou 2017-03-30 16:14:53 +08:00 committed by GitHub
commit 2092387e18
20 changed files with 132 additions and 58 deletions

View File

@ -18,8 +18,8 @@
<clr-icon shape="caret down"></clr-icon>
</button>
<div class="dropdown-menu">
<a href="javascript:void(0)" clrDropdownItem (click)='switchLanguage("en-us")' [class.lang-selected]='matchLang("en")'>English</a>
<a href="javascript:void(0)" clrDropdownItem (click)='switchLanguage("zh-cn")' [class.lang-selected]='matchLang("zh")'>中文简体</a>
<a href="javascript:void(0)" clrDropdownItem (click)='switchLanguage("en-us")' [class.lang-selected]='matchLang("en-us")'>English</a>
<a href="javascript:void(0)" clrDropdownItem (click)='switchLanguage("zh-cn")' [class.lang-selected]='matchLang("zh-cn")'>中文简体</a>
</div>
</clr-dropdown>
<clr-dropdown [clrMenuPosition]="'bottom-right'" class="dropdown" *ngIf="isSessionValid">

View File

@ -1,12 +1,12 @@
<clr-modal [(clrModalOpen)]="createProjectOpened" [clrModalStaticBackdrop]="staticBackdrop" [clrModalClosable]="closable">
<h3 class="modal-title">{{'PROJECT.NEW_PROJECT' | translate}}</h3>
<inline-alert class="modal-title" (confirmEvt)="confirmCancel($event)"></inline-alert>
<div class="modal-body">
<div class="modal-body" style="height: 12.8em; overflow-y: hidden;">
<form #projectForm="ngForm">
<section class="form-block">
<div class="form-group">
<label for="create_project_name" class="col-md-4 form-group-label-override">{{'PROJECT.NAME' | translate}}</label>
<label for="create_project_name" aria-haspopup="true" role="tooltip" [class.invalid]="projectName.invalid && (projectName.dirty || projectName.touched)" [class.valid]="projectName.valid" class="tooltip tooltip-validation tooltip-sm tooltip-bottom-right">
<label for="create_project_name" aria-haspopup="true" role="tooltip" [class.invalid]="projectName.invalid && (projectName.dirty || projectName.touched)" [class.valid]="projectName.valid" class="tooltip tooltip-validation tooltip-sm tooltip-bottom-left">
<input type="text" id="create_project_name" [(ngModel)]="project.name" name="name" size="20" required minlength="2" #projectName="ngModel" targetExists="PROJECT_NAME">
<span class="tooltip-content" *ngIf="projectName.errors && projectName.errors.required && (projectName.dirty || projectName.touched)">
{{'PROJECT.NAME_IS_REQUIRED' | translate}}
@ -26,6 +26,9 @@
<label for="create_project_public"></label>
</div>
</div>
<p class="inline-help-public">
{{'PROJECT.INLINE_HELP_PUBLIC' | translate }}
</p>
</section>
</form>
</div>

View File

@ -0,0 +1,12 @@
.inline-help-public {
color: #CCCCCC;
font-size: 12px;
letter-spacing: 0.01em;
margin-top: 0;
padding: 0 14px;
}
.form-group-label-override {
font-size: 14px;
font-weight: 400;
}

View File

@ -0,0 +1,4 @@
.form-group-label-override {
font-size: 14px;
font-weight: 400;
}

View File

@ -6,7 +6,7 @@
<section class="form-block">
<div class="form-group">
<label for="member_name" class="col-md-4 form-group-label-override">{{'MEMBER.NAME' | translate}}</label>
<label for="member_name" aria-haspopup="true" role="tooltip" [class.invalid]="memberName.invalid && (memberName.dirty || memberName.touched)" [class.valid]="memberName.valid" class="tooltip tooltip-validation tooltip-sm tooltip-bottom-right">
<label for="member_name" aria-haspopup="true" role="tooltip" [class.invalid]="memberName.invalid && (memberName.dirty || memberName.touched)" [class.valid]="memberName.valid" class="tooltip tooltip-validation tooltip-sm tooltip-bottom-left">
<input type="text" id="member_name" [(ngModel)]="member.username" name="name" size="20" #memberName="ngModel" required targetExists="MEMBER_NAME" [projectId]="projectId">
<span class="tooltip-content" *ngIf="memberName.errors && memberName.errors.required && (memberName.dirty || memberName.touched)">
{{ 'MEMBER.USERNAME_IS_REQUIRED' | translate }}

View File

@ -13,7 +13,8 @@ import { Member } from '../member';
@Component({
selector: 'add-member',
templateUrl: 'add-member.component.html'
templateUrl: 'add-member.component.html',
styleUrls: [ 'add-member.component.css' ]
})
export class AddMemberComponent implements AfterViewChecked {

View File

@ -5,4 +5,11 @@
.sub-nav-bg-color {
background-color: #fafafa;
}
.role-label {
color: #CCCCCC;
font-size: 14px;
font-style: italic;
letter-spacing: 0.01em;
}

View File

@ -1,7 +1,7 @@
<a *ngIf="hasSignedIn" [routerLink]="['/harbor', 'projects']">&lt; {{'PROJECT_DETAIL.PROJECTS' | translate}}</a>
<a *ngIf="!hasSignedIn" [routerLink]="['/harbor', 'sign-in']">&lt; {{'SEARCH.BACK' | translate}}</a>
<h1 class="sub-header-title">{{currentProject.name}} <span class="badge badge-light-blue" *ngIf="isMember">{{roleName | translate}}</span> <span class="badge badge-purple" *ngIf="isSystemAdmin">{{ 'MEMBER.SYS_ADMIN' | translate}}</span></h1>
<h1 class="sub-header-title">{{currentProject.name}} <span class="role-label" *ngIf="isMember">{{roleName | translate}}</span> <span class="role-label" *ngIf="isSystemAdmin">{{ 'MEMBER.SYS_ADMIN' | translate}}</span></h1>
<nav class="subnav sub-nav-bg-color">
<ul class="nav">
<li class="nav-item">

View File

@ -75,8 +75,14 @@ export class ProjectComponent implements OnInit, OnDestroy {
console.log('Successful delete project with ID:' + projectId);
this.retrieve();
},
error =>this.messageHandlerService.handleError(error)
);
error =>{
if(error && error.status === 412) {
this.messageHandlerService.showError('PROJECT.FAILED_TO_DELETE_PROJECT', '');
} else {
this.messageHandlerService.handleError(error);
}
}
);
}
});
@ -121,7 +127,7 @@ export class ProjectComponent implements OnInit, OnDestroy {
this.changedProjects = response.json();
},
error => this.messageHandlerService.handleError(error)
);
);
}
openModal(): void {

View File

@ -0,0 +1,4 @@
.form-group-label-override {
font-size: 14px;
font-weight: 400;
}

View File

@ -2,7 +2,7 @@
<h3 class="modal-title">{{modalTitle}}</h3>
<inline-alert class="modal-title" (confirmEvt)="confirmCancel($event)"></inline-alert>
<div class="modal-body">
<div class="alert alert-danger" *ngIf="!editable">
<div class="alert alert-warning" *ngIf="!editable">
<div class="alert-item">
<span class="alert-text">
{{'DESTINATION.CANNOT_EDIT' | translate}}
@ -13,8 +13,8 @@
<section class="form-block">
<div class="form-group">
<label for="destination_name" class="col-md-4 form-group-label-override">{{ 'DESTINATION.NAME' | translate }}<span style="color: red">*</span></label>
<label class="col-md-8" for="destination_name" aria-haspopup="true" role="tooltip" [class.invalid]="targetName.errors && (targetName.dirty || targetName.touched)" [class.valid]="targetName.valid" class="tooltip tooltip-validation tooltip-sm tooltip-bottom-right">
<input type="text" id="destination_name" [disabled]="testOngoing || !editable" [(ngModel)]="target.name" name="targetName" size="20" #targetName="ngModel" value="" required>
<label class="col-md-8" for="destination_name" aria-haspopup="true" role="tooltip" [class.invalid]="targetName.errors && (targetName.dirty || targetName.touched)" [class.valid]="targetName.valid" class="tooltip tooltip-validation tooltip-sm tooltip-bottom-left">
<input type="text" id="destination_name" [disabled]="testOngoing" [readonly]="!editable" [(ngModel)]="target.name" name="targetName" size="20" #targetName="ngModel" value="" required>
<span class="tooltip-content" *ngIf="targetName.errors && targetName.errors.required && (targetName.dirty || targetName.touched)">
{{ 'DESTINATION.NAME_IS_REQUIRED' | translate }}
</span>
@ -22,8 +22,8 @@
</div>
<div class="form-group">
<label for="destination_url" class="col-md-4 form-group-label-override">{{ 'DESTINATION.URL' | translate }}<span style="color: red">*</span></label>
<label class="col-md-8" for="destination_url" aria-haspopup="true" role="tooltip" [class.invalid]="targetEndpoint.errors && (targetEndpoint.dirty || targetEndpoint.touched)" [class.valid]="targetEndpoint.valid" class="tooltip tooltip-validation tooltip-sm tooltip-bottom-right">
<input type="text" id="destination_url" [disabled]="testOngoing || !editable" [(ngModel)]="target.endpoint" size="20" name="endpointUrl" #targetEndpoint="ngModel" required>
<label class="col-md-8" for="destination_url" aria-haspopup="true" role="tooltip" [class.invalid]="targetEndpoint.errors && (targetEndpoint.dirty || targetEndpoint.touched)" [class.valid]="targetEndpoint.valid" class="tooltip tooltip-validation tooltip-sm tooltip-bottom-left">
<input type="text" id="destination_url" [disabled]="testOngoing" [readonly]="!editable" [(ngModel)]="target.endpoint" size="20" name="endpointUrl" #targetEndpoint="ngModel" required>
<span class="tooltip-content" *ngIf="targetEndpoint.errors && targetEndpoint.errors.required && (targetEndpoint.dirty || targetEndpoint.touched)">
{{ 'DESTINATION.URL_IS_REQUIRED' | translate }}
</span>
@ -31,11 +31,11 @@
</div>
<div class="form-group">
<label for="destination_username" class="col-md-4 form-group-label-override">{{ 'DESTINATION.USERNAME' | translate }}</label>
<input type="text" class="col-md-8" id="destination_username" [disabled]="testOngoing || !editable" [(ngModel)]="target.username" size="20" name="username" #username="ngModel">
<input type="text" class="col-md-8" id="destination_username" [disabled]="testOngoing" [readonly]="!editable" [(ngModel)]="target.username" size="20" name="username" #username="ngModel">
</div>
<div class="form-group">
<label for="destination_password" class="col-md-4 form-group-label-override">{{ 'DESTINATION.PASSWORD' | translate }}</label>
<input type="password" class="col-md-8" id="destination_password" [disabled]="testOngoing || !editable" [(ngModel)]="target.password" size="20" name="password" #password="ngModel">
<input type="password" class="col-md-8" id="destination_password" [disabled]="testOngoing" [readonly]="!editable" [(ngModel)]="target.password" size="20" name="password" #password="ngModel">
</div>
<div class="form-group">
<label for="spin" class="col-md-4"></label>

View File

@ -13,7 +13,8 @@ import { TranslateService } from '@ngx-translate/core';
@Component({
selector: 'create-edit-destination',
templateUrl: './create-edit-destination.component.html'
templateUrl: './create-edit-destination.component.html',
styleUrls: [ 'create-edit-destination.component.css' ]
})
export class CreateEditDestinationComponent implements AfterViewChecked {

View File

@ -1,6 +1,7 @@
import { Component, Input, Output, EventEmitter } from '@angular/core';
import { Job } from '../job';
import { State } from 'clarity-angular';
import { MessageHandlerService } from '../../shared/message-handler/message-handler.service';
@Component({
selector: 'list-job',
@ -12,10 +13,18 @@ export class ListJobComponent {
@Input() totalPage: number;
@Output() paginate = new EventEmitter<State>();
constructor(private messageHandlerService: MessageHandlerService) {}
pageOffset: number = 1;
refresh(state: State) {
if(this.jobs) {
for(let i = 0; i < this.jobs.length; i++) {
let j = this.jobs[i];
if(j.status === 'retrying' || j.status === 'error') {
this.messageHandlerService.showError('REPLICATION.FOUND_ERROR_IN_JOBS', '');
}
}
this.paginate.emit(state);
}
}

View File

@ -30,7 +30,7 @@
<h5 class="flex-items-xs-bottom option-left-down" style="margin-left: 14px;">{{'REPLICATION.REPLICATION_JOBS' | translate}}</h5>
<div class="flex-items-xs-bottom option-right-down">
<button class="btn btn-link" (click)="toggleSearchJobOptionalName(currentJobSearchOption)">{{toggleJobSearchOption[currentJobSearchOption] | translate}}</button>
<grid-filter filterPlaceholder='{{"REPLICATION.FILTER_POLICIES_PLACEHOLDER" | translate}}' (filter)="doSearchJobs($event)"></grid-filter>
<grid-filter filterPlaceholder='{{"REPLICATION.FILTER_JOBS_PLACEHOLDER" | translate}}' (filter)="doSearchJobs($event)"></grid-filter>
<a href="javascript:void(0)" (click)="refreshJobs()">
<clr-icon shape="refresh"></clr-icon>
</a>

View File

@ -0,0 +1,4 @@
.form-group-label-override {
font-size: 14px;
font-weight: 400;
}

View File

@ -1,10 +1,10 @@
<clr-modal [(clrModalOpen)]="createEditPolicyOpened" [clrModalStaticBackdrop]="staticBackdrop" [clrModalClosable]="closable">
<h3 class="modal-title">{{modalTitle}}</h3>
<inline-alert class="modal-title" (confirmEvt)="confirmCancel($event)"></inline-alert>
<div class="modal-body">
<div class="modal-body" style="max-height: 85vh;">
<form #policyForm="ngForm">
<section class="form-block">
<div class="alert alert-danger" *ngIf="readonly">
<div class="alert alert-warning" *ngIf="readonly">
<div class="alert-item">
<span class="alert-text">
{{'REPLICATION.CANNOT_EDIT' | translate}}
@ -13,8 +13,8 @@
</div>
<div class="form-group">
<label for="policy_name" class="col-md-4 form-group-label-override">{{'REPLICATION.NAME' | translate}}<span style="color: red">*</span></label>
<label for="policy_name" class="col-md-8" aria-haspopup="true" role="tooltip" [class.invalid]="name.errors && (name.dirty || name.touched)" [class.valid]="name.valid" class="tooltip tooltip-validation tooltip-sm tooltip-bottom-right">
<input type="text" id="policy_name" [(ngModel)]="createEditPolicy.name" name="name" #name="ngModel" required [disabled]="readonly">
<label for="policy_name" class="col-md-8" aria-haspopup="true" role="tooltip" [class.invalid]="name.errors && (name.dirty || name.touched)" [class.valid]="name.valid" class="tooltip tooltip-validation tooltip-sm tooltip-bottom-left">
<input type="text" id="policy_name" [(ngModel)]="createEditPolicy.name" name="name" size="20" #name="ngModel" required [readonly]="readonly">
<span class="tooltip-content" *ngIf="name.errors && name.errors.required && (name.dirty || name.touched)">
{{'REPLICATION.NAME_IS_REQUIRED' | translate}}
</span>
@ -22,7 +22,7 @@
</div>
<div class="form-group">
<label for="policy_description" class="col-md-4 form-group-label-override">{{'REPLICATION.DESCRIPTION' | translate}}</label>
<input type="text" class="col-md-8" id="policy_description" [(ngModel)]="createEditPolicy.description" name="description" size="20" #description="ngModel" [disabled]="readonly">
<textarea class="col-md-8" id="policy_description" row="3" [(ngModel)]="createEditPolicy.description" name="description" size="20" #description="ngModel" [readonly]="readonly"></textarea>
</div>
<div class="form-group">
<label class="col-md-4 form-group-label-override">{{'REPLICATION.ENABLE' | translate}}</label>
@ -38,7 +38,7 @@
<option *ngFor="let t of targets" [value]="t.id" [selected]="t.id == createEditPolicy.targetId">{{t.name}}</option>
</select>
</div>
<label class="col-md-8" *ngIf="isCreateDestination" for="destination_name" aria-haspopup="true" role="tooltip" [class.invalid]="targetName.errors && (targetName.dirty || targetName.touched)" [class.valid]="targetName.valid" class="tooltip tooltip-validation tooltip-sm tooltip-bottom-right">
<label class="col-md-8" *ngIf="isCreateDestination" for="destination_name" aria-haspopup="true" role="tooltip" [class.invalid]="targetName.errors && (targetName.dirty || targetName.touched)" [class.valid]="targetName.valid" class="tooltip tooltip-validation tooltip-sm tooltip-bottom-left">
<input type="text" id="destination_name" [(ngModel)]="createEditPolicy.targetName" name="targetName" size="8" #targetName="ngModel" value="" required>
<span class="tooltip-content" *ngIf="targetName.errors && targetName.errors.required && (targetName.dirty || targetName.touched)">
{{'REPLICATION.DESTINATION_NAME_IS_REQUIRED' | translate}}
@ -51,8 +51,8 @@
</div>
<div class="form-group">
<label for="destination_url" class="col-md-4 form-group-label-override">{{'REPLICATION.DESTINATION_URL' | translate}}<span style="color: red">*</span></label>
<label for="destination_url" class="col-md-8" aria-haspopup="true" role="tooltip" [class.invalid]="endpointUrl.errors && (endpointUrl.dirty || endpointUrl.touched)" [class.valid]="endpointUrl.valid" class="tooltip tooltip-validation tooltip-sm tooltip-bottom-right">
<input type="text" id="destination_url" [disabled]="testOngoing || readonly" [(ngModel)]="createEditPolicy.endpointUrl" size="20" name="endpointUrl" required #endpointUrl="ngModel">
<label for="destination_url" class="col-md-8" aria-haspopup="true" role="tooltip" [class.invalid]="endpointUrl.errors && (endpointUrl.dirty || endpointUrl.touched)" [class.valid]="endpointUrl.valid" class="tooltip tooltip-validation tooltip-sm tooltip-bottom-left">
<input type="text" id="destination_url" [disabled]="testOngoing" [readonly]="readonly || !isCreateDestination" [(ngModel)]="createEditPolicy.endpointUrl" size="20" name="endpointUrl" required #endpointUrl="ngModel">
<span class="tooltip-content" *ngIf="endpointUrl.errors && endpointUrl.errors.required && (endpointUrl.dirty || endpointUrl.touched)">
{{'REPLICATION.DESTINATION_URL_IS_REQUIRED' | translate}}
</span>
@ -60,11 +60,11 @@
</div>
<div class="form-group">
<label for="destination_username" class="col-md-4 form-group-label-override">{{'REPLICATION.DESTINATION_USERNAME' | translate}}</label>
<input type="text" class="col-md-8" id="destination_username" [disabled]="testOngoing || readonly" [(ngModel)]="createEditPolicy.username" size="20" name="username" #username="ngModel">
<input type="text" class="col-md-8" id="destination_username" [disabled]="testOngoing" [readonly]="readonly || !isCreateDestination" [(ngModel)]="createEditPolicy.username" size="20" name="username" #username="ngModel">
</div>
<div class="form-group">
<label for="destination_password" class="col-md-4 form-group-label-override">{{'REPLICATION.DESTINATION_PASSWORD' | translate}}</label>
<input type="password" class="col-md-8" id="destination_password" [disabled]="testOngoing || readonly" [(ngModel)]="createEditPolicy.password" size="20" name="password" #password="ngModel">
<input type="password" class="col-md-8" id="destination_password" [disabled]="testOngoing" [readonly]="readonly || !isCreateDestination" [(ngModel)]="createEditPolicy.password" size="20" name="password" #password="ngModel">
</div>
<div class="form-group">
<label for="spin" class="col-md-4"></label>
@ -77,6 +77,6 @@
<div class="modal-footer">
<button type="button" class="btn btn-outline" (click)="testConnection()" [disabled]="testOngoing">{{'REPLICATION.TEST_CONNECTION' | translate}}</button>
<button type="button" class="btn btn-outline" (click)="onCancel()">{{'BUTTON.CANCEL' | translate }}</button>
<button type="submit" class="btn btn-primary" [disabled]="!policyForm.form.valid" (click)="onSubmit()">{{'BUTTON.OK' | translate}}</button>
<button type="submit" class="btn btn-primary" [disabled]="!policyForm.form.valid || testOngoing || readonly" (click)="onSubmit()">{{'BUTTON.OK' | translate}}</button>
</div>
</clr-modal>

View File

@ -17,7 +17,8 @@ import { TranslateService } from '@ngx-translate/core';
@Component({
selector: 'create-edit-policy',
templateUrl: 'create-edit-policy.component.html'
templateUrl: 'create-edit-policy.component.html',
styleUrls: [ 'create-edit-policy.component.css' ]
})
export class CreateEditPolicyComponent implements OnInit, AfterViewChecked {
@ -195,6 +196,8 @@ export class CreateEditPolicyComponent implements OnInit, AfterViewChecked {
if(this.messageHandlerService.isAppLevel(error)) {
this.messageHandlerService.handleError(error);
this.createEditPolicyOpened = false;
} else if (error.status === 409) {
this.inlineAlert.showInlineError('REPLICATION.POLICY_ALREADY_EXISTS');
} else {
this.inlineAlert.showInlineError(error);
}
@ -217,6 +220,8 @@ export class CreateEditPolicyComponent implements OnInit, AfterViewChecked {
if(this.messageHandlerService.isAppLevel(error)) {
this.messageHandlerService.handleError(error);
this.createEditPolicyOpened = false;
} else if (error.status === 409) {
this.inlineAlert.showInlineError('REPLICATION.POLICY_ALREADY_EXISTS');
} else {
this.inlineAlert.showInlineError(error);
}
@ -240,6 +245,8 @@ export class CreateEditPolicyComponent implements OnInit, AfterViewChecked {
if(this.messageHandlerService.isAppLevel(error)) {
this.messageHandlerService.handleError(error);
this.createEditPolicyOpened = false;
} else if (error.status === 409) {
this.inlineAlert.showInlineError('REPLICATION.POLICY_ALREADY_EXISTS');
} else {
this.inlineAlert.showInlineError(error);
}

View File

@ -75,7 +75,13 @@ export class ListPolicyComponent implements OnDestroy {
console.log('Successful delete policy with ID:' + message.data);
this.reload.emit(true);
},
error => this.messageHandlerService.handleError(error)
error => {
if(error && error.status === 412) {
this.messageHandlerService.handleError('REPLICATION.FAILED_TO_DELETE_POLICY_ENABLED');
} else {
this.messageHandlerService.handleError(error);
}
}
);
}
}

View File

@ -146,7 +146,9 @@
"REPLICATION_RULE": "Replication Rule",
"CREATED_SUCCESS": "Created project successfully.",
"DELETED_SUCCESS": "Deleted project successfully.",
"TOGGLED_SUCCESS": "Toggled project successfully."
"TOGGLED_SUCCESS": "Toggled project successfully.",
"FAILED_TO_DELETE_PROJECT": "Project contains repositories or replication rules can not be deleted.",
"INLINE_HELP_PUBLIC": "When a project is set to public, anyone has read permission to the repositories under this project, and the user does not need to run \"docker login\" before pulling images under this project."
},
"PROJECT_DETAIL": {
"REPOSITORIES": "Repositories",
@ -204,7 +206,7 @@
"FILTER_JOBS_PLACEHOLDER": "Filter Jobs",
"DELETION_TITLE": "Confirm Rule Deletion",
"DELETION_SUMMARY": "Do you want to delete rule {{param}}?",
"FILTER_TARGETS_PLACEHOLDER": "Filter Targets",
"FILTER_TARGETS_PLACEHOLDER": "Filter Endpoints",
"DELETION_TITLE_TARGET": "Confirm Endpoint Deletion",
"DELETION_SUMMARY_TARGET": "Do you want to delete the endpoint {{param}}?",
"ADD_POLICY": "New Replication Rule",
@ -250,15 +252,18 @@
"LOGS": "Logs",
"ITEMS": "item(s)",
"TOGGLE_ENABLE_TITLE": "Enable Rule",
"CONFIRM_TOGGLE_ENABLE_POLICY": "After enabling the replication rule, all repositories under the project will be replicated to the destination registry. Please confirm to continue.",
"CONFIRM_TOGGLE_ENABLE_POLICY": "After enabling the replication rule, all repositories under the project \nwill be replicated to the destination registry. \nPlease confirm to continue.",
"TOGGLE_DISABLE_TITLE": "Disable Rule",
"CONFIRM_TOGGLE_DISABLE_POLICY": "After disabling the rule, all unfinished replication jobs of this rule will be stopped and canceled. Please confirm to continue.",
"CONFIRM_TOGGLE_DISABLE_POLICY": "After disabling the rule, all unfinished replication jobs of this rule \nwill be stopped and canceled. \nPlease confirm to continue.",
"CREATED_SUCCESS": "Created replication rule successfully.",
"UPDATED_SUCCESS": "Updated replication rule successfully.",
"DELETED_SUCCESS": "Deleted replication rule successfully.",
"DELETED_FAILED": "Deleted replication rule failed.",
"TOGGLED_SUCCESS": "Toggled replication rule status successfully.",
"CANNOT_EDIT": "Replication rule cannot be changed while it is enabled."
"CANNOT_EDIT": "Replication rule cannot be changed while it is enabled.",
"POLICY_ALREADY_EXISTS": "Replication rule already exists.",
"FAILED_TO_DELETE_POLICY_ENABLED": "Cannot delete rule: rule has unfinished job(s) or rule is enabled.",
"FOUND_ERROR_IN_JOBS": "Found errors in the replication job(s), please check."
},
"DESTINATION": {
"NEW_ENDPOINT": "New Endpoint",

View File

@ -128,7 +128,7 @@
"PUBLIC": "公开",
"PRIVATE": "私有",
"MAKE": "设为",
"NEW_POLICY": "新建策略",
"NEW_POLICY": "新建规则",
"DELETE": "删除",
"MY_PROJECTS": "所有项目",
"PUBLIC_PROJECTS": "公开项目",
@ -143,10 +143,12 @@
"DELETION_TITLE": "删除项目确认",
"DELETION_SUMMARY": "你确认删除项目 {{param}}",
"FILTER_PLACEHOLDER": "过滤项目",
"REPLICATION_RULE": "复制策略",
"REPLICATION_RULE": "复制规则",
"CREATED_SUCCESS": "创建项目成功。",
"DELETED_SUCCESS": "删除项目成功。",
"TOGGLED_SUCCESS": "切换状态成功。"
"TOGGLED_SUCCESS": "切换状态成功。",
"FAILED_TO_DELETE_PROJECT": "项目包含镜像仓库或复制规则,无法删除。",
"INLINE_HELP_PUBLIC": "当项目设为公开后任何人都有此项目下镜像的读权限。命令行用户不需要“docker login”就可以拉取此项目下的镜像。"
},
"PROJECT_DETAIL": {
"REPOSITORIES": "镜像仓库",
@ -197,19 +199,19 @@
"FILTER_PLACEHOLDER": "过滤日志"
},
"REPLICATION": {
"REPLICATION_RULE": "复制策略",
"NEW_REPLICATION_RULE": "新建策略",
"REPLICATION_RULE": "复制规则",
"NEW_REPLICATION_RULE": "新建规则",
"ENDPOINTS": "目标",
"FILTER_POLICIES_PLACEHOLDER": "过滤策略",
"FILTER_POLICIES_PLACEHOLDER": "过滤规则",
"FILTER_JOBS_PLACEHOLDER": "过滤任务",
"DELETION_TITLE": "删除策略确认",
"DELETION_SUMMARY": "确认删除策略 {{param}}?",
"DELETION_TITLE": "删除规则确认",
"DELETION_SUMMARY": "确认删除规则 {{param}}?",
"FILTER_TARGETS_PLACEHOLDER": "过滤目标",
"DELETION_TITLE_TARGET": "删除目标确认",
"DELETION_SUMMARY_TARGET": "确认删除目标 {{param}}?",
"ADD_POLICY": "新建策略",
"EDIT_POLICY": "修改策略",
"DELETE_POLICY": "删除策略",
"ADD_POLICY": "新建规则",
"EDIT_POLICY": "修改规则",
"DELETE_POLICY": "删除规则",
"TEST_CONNECTION": "测试连接",
"TESTING_CONNECTION": "正在测试连接...",
"TEST_CONNECTION_SUCCESS": "测试连接成功。",
@ -249,16 +251,19 @@
"END_TIME": "结束时间",
"LOGS": "日志",
"ITEMS": "条记录",
"TOGGLE_ENABLE_TITLE": "启用策略",
"CONFIRM_TOGGLE_ENABLE_POLICY": "启用策略后,该项目下的所有镜像仓库将复制到目标实例。请确认继续。",
"TOGGLE_DISABLE_TITLE": "停用策略",
"CONFIRM_TOGGLE_DISABLE_POLICY": "停用策略后,所有未完成的复制任务将被终止和取消。请确认继续。",
"CREATED_SUCCESS": "创建复制策略成功。",
"UPDATED_SUCCESS": "更新复制策略成功。",
"DELETED_SUCCESS": "删除复制策略成功。",
"DELETED_FAILED": "删除复制策略失败。",
"TOGGLED_SUCCESS": "切换复制策略状态成功。",
"CANNOT_EDIT": "当复制规则启用时无法修改。"
"TOGGLE_ENABLE_TITLE": "启用规则",
"CONFIRM_TOGGLE_ENABLE_POLICY": "启用规则后,该项目下的所有镜像仓库将复制到目标实例。请确认继续。",
"TOGGLE_DISABLE_TITLE": "停用规则",
"CONFIRM_TOGGLE_DISABLE_POLICY": "停用规则后,所有未完成的复制任务将被终止和取消。请确认继续。",
"CREATED_SUCCESS": "创建复制规则成功。",
"UPDATED_SUCCESS": "更新复制规则成功。",
"DELETED_SUCCESS": "删除复制规则成功。",
"DELETED_FAILED": "删除复制规则失败。",
"TOGGLED_SUCCESS": "切换复制规则状态成功。",
"CANNOT_EDIT": "当复制规则启用时无法修改。",
"POLICY_ALREADY_EXISTS": "规则已存在。",
"FAILED_TO_DELETE_POLICY_ENABLED": "删除复制规则失败: 仍有未完成的任务或规则未停用。",
"FOUND_ERROR_IN_JOBS": "复制任务中包含错误,请检查。"
},
"DESTINATION": {
"NEW_ENDPOINT": "新建目标",