Merge pull request #4076 from pengpengshui/batchDelection

Modify create multiple replication rules with same name issue
This commit is contained in:
pengpengshui 2018-01-23 15:55:58 +08:00 committed by GitHub
commit f18ad3259e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 72 additions and 19 deletions

View File

@ -24,7 +24,7 @@ export const CONFIRMATION_DIALOG_STYLE: string = `
.batchInfoUl li {line-height: 24px;border-bottom: 1px solid #e8e8e8;}
.batchInfoUl li span:first-child {padding-right: 20px; width: 240px; display: inline-block; color:#666;
text-overflow: ellipsis; overflow: hidden; vertical-align: middle;}
.batchInfoUl li span:last-child {width: 230px; display: inline-block; color:#666;}
.batchInfoUl li span:last-child {width: 220px; display: inline-block; color:#666;}
.batchInfoUl li span i {display: inline-block; line-height: 1.2em; font-size: 0.8em; color: #999;}
.batchInfoUl li span a{cursor: pointer; text-decoration: underline;}
`;

View File

@ -13,7 +13,7 @@ export const LIST_REPLICATION_RULE_TEMPLATE: string = `
<clr-dg-column [clrDgField]="'projects'" *ngIf="!projectScope">{{'REPLICATION.PROJECT' | translate}}</clr-dg-column>
<clr-dg-column [clrDgField]="'description'">{{'REPLICATION.DESCRIPTION' | translate}}</clr-dg-column>
<clr-dg-column [clrDgField]="'targets'">{{'REPLICATION.DESTINATION_NAME' | translate}}</clr-dg-column>
<clr-dg-column [clrDgField]="'trigger'">{{'REPLICATION.MODE' | translate}}</clr-dg-column>
<clr-dg-column [clrDgField]="'trigger'">{{'REPLICATION.TRIGGER_MODE' | translate}}</clr-dg-column>
<clr-dg-placeholder>{{'REPLICATION.PLACEHOLDER' | translate }}</clr-dg-placeholder>
<clr-dg-row *clrDgItems="let p of changedRules" [clrDgItem]="p" [style.backgroundColor]="(projectScope && withReplicationJob && selectedId === p.id) ? '#eee' : ''">
<clr-dg-cell (click)="selectRule(p)">{{p.name}}</clr-dg-cell>

View File

@ -40,7 +40,7 @@ export const REPLICATION_TEMPLATE: string = `
<div *ngIf="withReplicationJob" class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
<clr-datagrid [clrDgLoading]="jobsLoading" (clrDgRefresh)="clrLoadJobs($event)"><clr-dg-action-bar>
<div class="btn-group">
<button type="button" class="btn btn-sm btn-secondary" [hidden]="!(jobs && jobs.length>0 && isSystemAdmin)" (click)="stopJobs()">{{'REPLICATION.STOPJOB' | translate}}</button>
<button type="button" class="btn btn-sm btn-secondary" *ngIf="isSystemAdmin" [disabled]="!(jobs && jobs.length>0) || isStopOnGoing" (click)="stopJobs()">{{'REPLICATION.STOPJOB' | translate}}</button>
</div>
</clr-dg-action-bar>
<clr-dg-column [clrDgField]="'repository'">{{'REPLICATION.NAME' | translate}}</clr-dg-column>

View File

@ -111,6 +111,7 @@ export class ReplicationComponent implements OnInit, OnDestroy {
rules: ReplicationRule[];
loading: boolean;
isStopOnGoing: boolean;
jobs: ReplicationJobItem[];
batchDelectionInfos: BatchInfo[] = [];
@ -362,8 +363,12 @@ export class ReplicationComponent implements OnInit, OnDestroy {
stopJobs() {
if (this.jobs && this.jobs.length) {
this.isStopOnGoing = true;
toPromise(this.replicationService.stopJobs(this.jobs[0].policy_id))
.then(res => {this.refreshJobs(); })
.then(res => {
this.refreshJobs();
this.isStopOnGoing = false;
})
.catch(error => this.errorHandler.error(error));
}
}

View File

@ -36,8 +36,8 @@ export const TAG_TEMPLATE = `
<clr-dg-column style="width: 140px;" *ngIf="withClair">{{'REPOSITORY.VULNERABILITY' | translate}}</clr-dg-column>
<clr-dg-column style="width: 80px;" *ngIf="withNotary">{{'REPOSITORY.SIGNED' | translate}}</clr-dg-column>
<clr-dg-column style="min-width: 130px;">{{'REPOSITORY.AUTHOR' | translate}}</clr-dg-column>
<clr-dg-column style="width: 160px;"[clrDgSortBy]="createdComparator">{{'REPOSITORY.CREATED' | translate}}</clr-dg-column>
<clr-dg-column style="width: 80px;" [clrDgField]="'docker_version'" *ngIf="!withClair">{{'REPOSITORY.DOCKER_VERSION' | translate}}</clr-dg-column>
<clr-dg-column style="width: 150px;"[clrDgSortBy]="createdComparator">{{'REPOSITORY.CREATED' | translate}}</clr-dg-column>
<clr-dg-column style="width: 140px;" [clrDgField]="'docker_version'" *ngIf="!withClair">{{'REPOSITORY.DOCKER_VERSION' | translate}}</clr-dg-column>
<clr-dg-placeholder>{{'TAG.PLACEHOLDER' | translate }}</clr-dg-placeholder>
<clr-dg-row *ngFor="let t of tags" [clrDgItem]='t'>
<clr-dg-cell class="truncated" style="width: 160px;" [ngSwitch]="withClair">
@ -60,8 +60,8 @@ export const TAG_TEMPLATE = `
</a>
</clr-dg-cell>
<clr-dg-cell class="truncated" style="min-width: 130px;" title="{{t.author}}">{{t.author}}</clr-dg-cell>
<clr-dg-cell style="width: 160px;">{{t.created | date: 'short'}}</clr-dg-cell>
<clr-dg-cell style="width: 80px;" *ngIf="!withClair">{{t.docker_version}}</clr-dg-cell>
<clr-dg-cell style="width: 150px;">{{t.created | date: 'short'}}</clr-dg-cell>
<clr-dg-cell style="width: 140px;" *ngIf="!withClair">{{t.docker_version}}</clr-dg-cell>
</clr-dg-row>
<clr-dg-footer>
<span *ngIf="pagination.totalItems">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'REPOSITORY.OF' | translate}}</span>

View File

@ -31,7 +31,7 @@
"clarity-icons": "^0.10.17",
"clarity-ui": "^0.10.17",
"core-js": "^2.4.1",
"harbor-ui": "0.6.25",
"harbor-ui": "0.6.28",
"intl": "^1.2.5",
"mutationobserver-shim": "^0.3.2",
"ngx-cookie": "^1.0.0",

View File

@ -48,6 +48,7 @@ export class ReplicationRuleComponent implements OnInit, OnDestroy {
inProgress: boolean = false;
inNameChecking: boolean = false;
isRuleNameExist: boolean = false;
isSubmitOver: boolean = false;
nameChecker: Subject<string> = new Subject<string>();
confirmSub: Subscription;
@ -147,7 +148,7 @@ export class ReplicationRuleComponent implements OnInit, OnDestroy {
}
get isVaild() {
return !(this.isRuleNameExist || this.noProjectInfo || this.noEndpointInfo);
return !(this.isRuleNameExist || this.noProjectInfo || this.noEndpointInfo || this.inProgress || this.isSubmitOver);
}
createForm() {
@ -412,6 +413,7 @@ export class ReplicationRuleComponent implements OnInit, OnDestroy {
onSubmit() {
// add new Replication rule
this.inProgress = true;
let copyRuleForm: ReplicationRule = this.ruleForm.value;
copyRuleForm.trigger = this.setTriggerVaule(copyRuleForm.trigger);
if (!this.policyId) {
@ -419,6 +421,7 @@ export class ReplicationRuleComponent implements OnInit, OnDestroy {
.then(() => {
this.msgHandler.showSuccess('REPLICATION.CREATED_SUCCESS');
this.inProgress = false;
this.isSubmitOver = true;
setTimeout(() => {
this.copyUpdateForm = Object.assign({}, this.ruleForm.value);
if (this.projectId) {
@ -426,7 +429,6 @@ export class ReplicationRuleComponent implements OnInit, OnDestroy {
}else {
this.router.navigate(['/harbor/replications']);
}
}, 2000);
}).catch((error: any) => {
@ -438,6 +440,7 @@ export class ReplicationRuleComponent implements OnInit, OnDestroy {
.then(() => {
this.msgHandler.showSuccess('REPLICATION.UPDATED_SUCCESS');
this.inProgress = false;
this.isSubmitOver = true;
setTimeout(() => {
this.copyUpdateForm = Object.assign({}, this.ruleForm.value);
if (this.projectId) {
@ -452,7 +455,7 @@ export class ReplicationRuleComponent implements OnInit, OnDestroy {
this.msgHandler.handleError(error);
});
}
this.inProgress = true;
}
openModal() {

View File

@ -72,23 +72,32 @@
<label class="col-md-4 form-group-label-override">{{'REPLICATION.MODE' | translate}}</label>
<div formGroupName="trigger">
<!--on trigger-->
<div class="select floatSet">
<div class="select floatSet pull-left">
<select id="ruleTrigger" formControlName="kind" (change)="selectTrigger($event)">
<option *ngFor="let triggerName of triggerNames" value="{{triggerName}}">{{triggerName}}</option>
<option value="Immediate">{{'REPLICATION.IMMEDIATE' | translate}}</option>
<option value="Scheduled">{{'REPLICATION.SCHEDULE' | translate}}</option>
<option value="Manual">{{'REPLICATION.MANUAL' | translate}}</option>
</select>
</div>
<!--on push-->
<div style="float: left;" formGroupName="schedule_param">
<div class="select floatSet" [hidden]="!isScheduleOpt">
<div class="select floatSet pull-left" [hidden]="!isScheduleOpt">
<select name="scheduleType" formControlName="type" (change)="selectSchedule($event)">
<option *ngFor="let scheduleName of scheduleNames" value="{{scheduleName}}">{{scheduleName}}</option>
<option value="Daily">{{'REPLICATION.DAILY' | translate}}</option>
<option value="Weekly">{{'REPLICATION.WEEKLY' | translate}}</option>
</select>
</div>
<!--weekly-->
<span style="float: left;" [hidden]="!weeklySchedule || !isScheduleOpt">on &nbsp;&nbsp;</span>
<div [hidden]="!weeklySchedule || !isScheduleOpt" class="select floatSet">
<div [hidden]="!weeklySchedule || !isScheduleOpt" class="select floatSet pull-left">
<select name="scheduleDay" formControlName="weekday">
<option *ngFor="let filter of weekly; let i = index" [value]="i+1">{{filter}}</option>
<option value="1">{{'WEEKLY.MONDAY' | translate}}</option>
<option value="2">{{'WEEKLY.TUESDAY' | translate}}</option>
<option value="3">{{'WEEKLY.WEDNESDAY' | translate}}</option>
<option value="4">{{'WEEKLY.THURSDAY' | translate}}</option>
<option value="5">{{'WEEKLY.FRIDAY' | translate}}</option>
<option value="6">{{'WEEKLY.SATURDAY' | translate}}</option>
<option value="7">{{'WEEKLY.SUNDAY' | translate}}</option>
</select>
</div>
<!--daily/time-->

View File

@ -23,6 +23,6 @@
.batchInfoUl li {line-height: 24px;border-bottom: 1px solid #e8e8e8;}
.batchInfoUl li span:first-child {padding-right: 20px; width: 240px; display: inline-block; color:#666;
text-overflow: ellipsis; overflow: hidden; vertical-align: middle;}
.batchInfoUl li span:last-child {width: 230px; display: inline-block; color:#666;}
.batchInfoUl li span:last-child {width: 220px; display: inline-block; color:#666;}
.batchInfoUl li span i {display: inline-block; line-height: 1.2em; font-size: 0.8em; color: #999;}
.batchInfoUl li span a{cursor: pointer; text-decoration: underline;}

View File

@ -326,10 +326,13 @@
"SCHEDULE": "Scheduled",
"MANUAL": "Manual",
"IMMEDIATE": "Immediate",
"DAILY": "Daily",
"WEEKLY": "Weekly",
"SETTING":"Options",
"TRIGGER":"Triggering Condition",
"TARGETS":"Target",
"MODE": "Mode",
"TRIGGER_MODE": "Trigger Mode",
"SOURCE": "Source",
"REPLICATE": "Replicate",
"DELETE_REMOTE_IMAGES":"Delete remote images when locally deleted",
@ -606,6 +609,15 @@
"COPY_ERROR": "Copy failed, please try to manually copy.",
"FILTER_FOR_TAGS": "Filter Tags"
},
"WEEKLY": {
"MONDAY": "Monday",
"TUESDAY": "Tuesday",
"WEDNESDAY": "Wednesday",
"THURSDAY": "Thursday",
"FRIDAY": "Friday",
"SATURDAY": "Saturday",
"SUNDAY": "Sunday"
},
"UNKNOWN_ERROR": "Unknown errors have occurred. Please try again later.",
"UNAUTHORIZED_ERROR": "Your session is invalid or has expired. You need to sign in to continue your action.",
"FORBIDDEN_ERROR": "You do not have the proper privileges to perform the action.",

View File

@ -326,10 +326,13 @@
"SCHEDULE": "Scheduled",
"MANUAL": "Manual",
"IMMEDIATE": "Immediate",
"DAILY": "Daily",
"WEEKLY": "Weekly",
"SETTING":"Options",
"TRIGGER":"Triggering Condition",
"TARGETS":"Target",
"MODE": "Mode",
"TRIGGER_MODE": "Trigger Mode",
"SOURCE": "Source",
"REPLICATE": "Replicate",
"DELETE_REMOTE_IMAGES":"Delete remote images when locally deleted",
@ -606,6 +609,15 @@
"COPY_ERROR": "Copy failed, please try to manually copy.",
"FILTER_FOR_TAGS": "Etiquetas de filtro"
},
"WEEKLY": {
"MONDAY": "Monday",
"TUESDAY": "Tuesday",
"WEDNESDAY": "Wednesday",
"THURSDAY": "Thursday",
"FRIDAY": "Friday",
"SATURDAY": "Saturday",
"SUNDAY": "Sunday"
},
"UNKNOWN_ERROR": "Ha ocurrido un error desconocido. Por favor, inténtelo de nuevo más tarde.",
"UNAUTHORIZED_ERROR": "La sesión no es válida o ha caducado. Necesita identificarse de nuevo para llevar a cabo esa acción.",
"FORBIDDEN_ERROR": "No tienes permisos para llevar a cabo esa acción.",

View File

@ -326,10 +326,13 @@
"SCHEDULE": "定时",
"MANUAL": "手动",
"IMMEDIATE": "即刻",
"DAILY": "每天",
"WEEKLY": "每周",
"SETTING":"设置",
"TRIGGER":"触发条件",
"TARGETS":"目标",
"MODE": "模式",
"TRIGGER_MODE": "触发模式",
"SOURCE": "资源",
"REPLICATE": "复制",
"DELETE_REMOTE_IMAGES":"删除本地镜像时同时也删除远程的镜像。",
@ -606,6 +609,15 @@
"COPY_ERROR": "拷贝失败,请尝试手动拷贝。",
"FILTER_FOR_TAGS": "过滤项目"
},
"WEEKLY": {
"MONDAY": "周一",
"TUESDAY": "周二",
"WEDNESDAY": "周三",
"THURSDAY": "周四",
"FRIDAY": "周五",
"SATURDAY": "周六",
"SUNDAY": "周日"
},
"UNKNOWN_ERROR": "发生未知错误,请稍后再试。",
"UNAUTHORIZED_ERROR": "会话无效或者已经过期, 请重新登录以继续。",
"FORBIDDEN_ERROR": "当前操作被禁止,请确认你有合法的权限。",