Merge pull request #7393 from pureshine/add-override

Fix replication frontend issues
This commit is contained in:
Wenkai Yin 2019-04-16 15:55:00 +08:00 committed by GitHub
commit 0f488e6011
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 128 additions and 52 deletions

View File

@ -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)) {

View File

@ -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>

View File

@ -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 = {

View File

@ -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: "" });
}

View File

@ -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);

View File

@ -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>

View File

@ -11,3 +11,7 @@
.status-width {
width: 105px;
}
.icon-style {
color: #C92100;
}

View File

@ -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
},
];

View File

@ -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>

View File

@ -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;

View File

@ -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);

View File

@ -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>

View File

@ -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
}
];

View File

@ -114,6 +114,7 @@ export interface ReplicationRule extends Base {
src_namespaces: string [];
dest_namespace?: string;
enabled: boolean;
override: boolean;
}
export class Filter {

View File

@ -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;

View File

@ -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",

View File

@ -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.",

View File

@ -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",

View File

@ -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",

View File

@ -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": "目标名称为必填项。",