mirror of
https://github.com/goharbor/harbor.git
synced 2024-12-29 12:07:56 +01:00
Merge pull request #7302 from pureshine/registry-update
Fix replication ui related issues
This commit is contained in:
commit
2644c52926
@ -31,8 +31,6 @@ import { InlineAlertComponent } from "../inline-alert/inline-alert.component";
|
|||||||
import { Endpoint } from "../service/interface";
|
import { Endpoint } from "../service/interface";
|
||||||
import { clone, compareValue, isEmptyObject } from "../utils";
|
import { clone, compareValue, isEmptyObject } from "../utils";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const FAKE_PASSWORD = "rjGcfuRu";
|
const FAKE_PASSWORD = "rjGcfuRu";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -72,14 +70,17 @@ export class CreateEditEndpointComponent
|
|||||||
private errorHandler: ErrorHandler,
|
private errorHandler: ErrorHandler,
|
||||||
private translateService: TranslateService,
|
private translateService: TranslateService,
|
||||||
private ref: ChangeDetectorRef
|
private ref: ChangeDetectorRef
|
||||||
) { }
|
) {}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.endpointService.getAdapters().subscribe(adapters => {
|
this.endpointService.getAdapters().subscribe(
|
||||||
this.adapterList = adapters || [];
|
adapters => {
|
||||||
}, error => {
|
this.adapterList = adapters || [];
|
||||||
this.errorHandler.error(error);
|
},
|
||||||
});
|
error => {
|
||||||
|
this.errorHandler.error(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public get isValid(): boolean {
|
public get isValid(): boolean {
|
||||||
@ -118,7 +119,7 @@ export class CreateEditEndpointComponent
|
|||||||
insecure: false,
|
insecure: false,
|
||||||
name: "",
|
name: "",
|
||||||
type: "harbor",
|
type: "harbor",
|
||||||
url: "",
|
url: ""
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,8 +168,8 @@ export class CreateEditEndpointComponent
|
|||||||
this.translateService
|
this.translateService
|
||||||
.get("DESTINATION.TITLE_EDIT")
|
.get("DESTINATION.TITLE_EDIT")
|
||||||
.subscribe(res => (this.modalTitle = res));
|
.subscribe(res => (this.modalTitle = res));
|
||||||
this.endpointService.getEndpoint(targetId)
|
this.endpointService.getEndpoint(targetId).subscribe(
|
||||||
.subscribe(target => {
|
target => {
|
||||||
this.target = target;
|
this.target = target;
|
||||||
// Keep data cache
|
// Keep data cache
|
||||||
this.initVal = clone(target);
|
this.initVal = clone(target);
|
||||||
@ -179,7 +180,9 @@ export class CreateEditEndpointComponent
|
|||||||
this.open();
|
this.open();
|
||||||
this.controlEnabled = true;
|
this.controlEnabled = true;
|
||||||
this.forceRefreshView(2000);
|
this.forceRefreshView(2000);
|
||||||
}, error => this.errorHandler.error(error));
|
},
|
||||||
|
error => this.errorHandler.error(error)
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
this.endpointId = "";
|
this.endpointId = "";
|
||||||
this.translateService
|
this.translateService
|
||||||
@ -213,18 +216,20 @@ export class CreateEditEndpointComponent
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.testOngoing = true;
|
this.testOngoing = true;
|
||||||
this.endpointService.pingEndpoint(payload)
|
this.endpointService.pingEndpoint(payload).subscribe(
|
||||||
.subscribe(response => {
|
response => {
|
||||||
this.inlineAlert.showInlineSuccess({
|
this.inlineAlert.showInlineSuccess({
|
||||||
message: "DESTINATION.TEST_CONNECTION_SUCCESS"
|
message: "DESTINATION.TEST_CONNECTION_SUCCESS"
|
||||||
});
|
});
|
||||||
this.forceRefreshView(2000);
|
this.forceRefreshView(2000);
|
||||||
this.testOngoing = false;
|
this.testOngoing = false;
|
||||||
}, error => {
|
},
|
||||||
|
error => {
|
||||||
this.inlineAlert.showInlineError("DESTINATION.TEST_CONNECTION_FAILURE");
|
this.inlineAlert.showInlineError("DESTINATION.TEST_CONNECTION_FAILURE");
|
||||||
this.forceRefreshView(2000);
|
this.forceRefreshView(2000);
|
||||||
this.testOngoing = false;
|
this.testOngoing = false;
|
||||||
});
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
onSubmit() {
|
onSubmit() {
|
||||||
@ -240,8 +245,8 @@ export class CreateEditEndpointComponent
|
|||||||
return; // Avoid duplicated submitting
|
return; // Avoid duplicated submitting
|
||||||
}
|
}
|
||||||
this.onGoing = true;
|
this.onGoing = true;
|
||||||
this.endpointService.createEndpoint(this.target)
|
this.endpointService.createEndpoint(this.target).subscribe(
|
||||||
.subscribe(response => {
|
response => {
|
||||||
this.translateService
|
this.translateService
|
||||||
.get("DESTINATION.CREATED_SUCCESS")
|
.get("DESTINATION.CREATED_SUCCESS")
|
||||||
.subscribe(res => this.errorHandler.info(res));
|
.subscribe(res => this.errorHandler.info(res));
|
||||||
@ -249,14 +254,16 @@ export class CreateEditEndpointComponent
|
|||||||
this.onGoing = false;
|
this.onGoing = false;
|
||||||
this.close();
|
this.close();
|
||||||
this.forceRefreshView(2000);
|
this.forceRefreshView(2000);
|
||||||
}, error => {
|
},
|
||||||
|
error => {
|
||||||
this.onGoing = false;
|
this.onGoing = false;
|
||||||
let errorMessageKey = this.handleErrorMessageKey(error.status);
|
let errorMessageKey = this.handleErrorMessageKey(error.status);
|
||||||
this.translateService.get(errorMessageKey).subscribe(res => {
|
this.translateService.get(errorMessageKey).subscribe(res => {
|
||||||
this.inlineAlert.showInlineError(res);
|
this.inlineAlert.showInlineError(res);
|
||||||
});
|
});
|
||||||
this.forceRefreshView(2000);
|
this.forceRefreshView(2000);
|
||||||
});
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateEndpoint() {
|
updateEndpoint() {
|
||||||
@ -272,6 +279,7 @@ export class CreateEditEndpointComponent
|
|||||||
if (isEmptyObject(changes)) {
|
if (isEmptyObject(changes)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let changekeys: { [key: string]: any } = Object.keys(changes);
|
let changekeys: { [key: string]: any } = Object.keys(changes);
|
||||||
|
|
||||||
changekeys.forEach((key: string) => {
|
changekeys.forEach((key: string) => {
|
||||||
@ -283,8 +291,8 @@ export class CreateEditEndpointComponent
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.onGoing = true;
|
this.onGoing = true;
|
||||||
this.endpointService.updateEndpoint(this.target.id, payload)
|
this.endpointService.updateEndpoint(this.target.id, payload).subscribe(
|
||||||
.subscribe(response => {
|
response => {
|
||||||
this.translateService
|
this.translateService
|
||||||
.get("DESTINATION.UPDATED_SUCCESS")
|
.get("DESTINATION.UPDATED_SUCCESS")
|
||||||
.subscribe(res => this.errorHandler.info(res));
|
.subscribe(res => this.errorHandler.info(res));
|
||||||
@ -292,14 +300,16 @@ export class CreateEditEndpointComponent
|
|||||||
this.close();
|
this.close();
|
||||||
this.onGoing = false;
|
this.onGoing = false;
|
||||||
this.forceRefreshView(2000);
|
this.forceRefreshView(2000);
|
||||||
}, error => {
|
},
|
||||||
|
error => {
|
||||||
let errorMessageKey = this.handleErrorMessageKey(error.status);
|
let errorMessageKey = this.handleErrorMessageKey(error.status);
|
||||||
this.translateService.get(errorMessageKey).subscribe(res => {
|
this.translateService.get(errorMessageKey).subscribe(res => {
|
||||||
this.inlineAlert.showInlineError(res);
|
this.inlineAlert.showInlineError(res);
|
||||||
});
|
});
|
||||||
this.onGoing = false;
|
this.onGoing = false;
|
||||||
this.forceRefreshView(2000);
|
this.forceRefreshView(2000);
|
||||||
});
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleErrorMessageKey(status: number): string {
|
handleErrorMessageKey(status: number): string {
|
||||||
@ -353,7 +363,6 @@ export class CreateEditEndpointComponent
|
|||||||
|
|
||||||
if (!compareValue(this.formValues, data)) {
|
if (!compareValue(this.formValues, data)) {
|
||||||
this.formValues = data;
|
this.formValues = data;
|
||||||
this.inlineAlert.close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -368,20 +377,36 @@ export class CreateEditEndpointComponent
|
|||||||
}
|
}
|
||||||
for (let prop of Object.keys(this.target)) {
|
for (let prop of Object.keys(this.target)) {
|
||||||
let field: any = this.initVal[prop];
|
let field: any = this.initVal[prop];
|
||||||
if (!compareValue(field, this.target[prop])) {
|
if (typeof field !== "object") {
|
||||||
changes[prop] = this.target[prop];
|
if (!compareValue(field, this.target[prop])) {
|
||||||
// Number
|
changes[prop] = this.target[prop];
|
||||||
if (typeof field === "number") {
|
// Number
|
||||||
changes[prop] = +changes[prop];
|
if (typeof field === "number") {
|
||||||
}
|
changes[prop] = +changes[prop];
|
||||||
|
}
|
||||||
|
|
||||||
// Trim string value
|
// Trim string value
|
||||||
if (typeof field === "string") {
|
if (typeof field === "string") {
|
||||||
changes[prop] = ("" + changes[prop]).trim();
|
changes[prop] = ("" + changes[prop]).trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (let pro of Object.keys(field)) {
|
||||||
|
if (!compareValue(field[pro], this.target[prop][pro])) {
|
||||||
|
changes[pro] = this.target[prop][pro];
|
||||||
|
// Number
|
||||||
|
if (typeof field[pro] === "number") {
|
||||||
|
changes[pro] = +changes[pro];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trim string value
|
||||||
|
if (typeof field[pro] === "string") {
|
||||||
|
changes[pro] = ("" + changes[pro]).trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return changes;
|
return changes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,8 @@
|
|||||||
<button type="button" class="btn btn-sm btn-secondary" *ngIf="hasDeleteReplicationPermission" [disabled]="!selectedRow" (click)="deleteRule(selectedRow)"><clr-icon shape="times" size="16"></clr-icon> {{'REPLICATION.DELETE_POLICY' | translate}}</button>
|
<button type="button" class="btn btn-sm btn-secondary" *ngIf="hasDeleteReplicationPermission" [disabled]="!selectedRow" (click)="deleteRule(selectedRow)"><clr-icon shape="times" size="16"></clr-icon> {{'REPLICATION.DELETE_POLICY' | translate}}</button>
|
||||||
<button type="button" class="btn btn-sm btn-secondary" *ngIf="hasExecuteReplicationPermission" [disabled]="!selectedRow" (click)="replicateRule(selectedRow)"><clr-icon shape="export" size="16"></clr-icon> {{'REPLICATION.REPLICATE' | translate}}</button>
|
<button type="button" class="btn btn-sm btn-secondary" *ngIf="hasExecuteReplicationPermission" [disabled]="!selectedRow" (click)="replicateRule(selectedRow)"><clr-icon shape="export" size="16"></clr-icon> {{'REPLICATION.REPLICATE' | translate}}</button>
|
||||||
</clr-dg-action-bar>
|
</clr-dg-action-bar>
|
||||||
<clr-dg-column [clrDgField]="'name'">{{'REPLICATION.NAME' | translate}}</clr-dg-column>
|
<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 class="min-width">{{'REPLICATION.SRC_NAMESPACE' | translate}}</clr-dg-column>
|
||||||
<clr-dg-column>{{'REPLICATION.REPLICATION_MODE' | translate}}</clr-dg-column>
|
<clr-dg-column>{{'REPLICATION.REPLICATION_MODE' | translate}}</clr-dg-column>
|
||||||
<clr-dg-column class="min-width">{{'REPLICATION.DESTINATION_NAMESPACE' | translate}}</clr-dg-column>
|
<clr-dg-column class="min-width">{{'REPLICATION.DESTINATION_NAMESPACE' | translate}}</clr-dg-column>
|
||||||
@ -15,6 +16,17 @@
|
|||||||
<clr-dg-placeholder>{{'REPLICATION.PLACEHOLDER' | translate }}</clr-dg-placeholder>
|
<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' : ''">
|
<clr-dg-row *clrDgItems="let p of changedRules; let i=index" [clrDgItem]="p" [style.backgroundColor]="(projectScope && withReplicationJob && selectedId === p.id) ? '#eee' : ''">
|
||||||
<clr-dg-cell>{{p.name}}</clr-dg-cell>
|
<clr-dg-cell>{{p.name}}</clr-dg-cell>
|
||||||
|
<clr-dg-cell class="status-width">
|
||||||
|
<div [ngSwitch]="p.enabled">
|
||||||
|
<clr-tooltip *ngSwitchCase="false" class="tooltip-lg">
|
||||||
|
<clr-icon clrTooltipTrigger shape="exclamation-triangle" class="is-warning text-alignment" size="22"></clr-icon>Disabled
|
||||||
|
<clr-tooltip-content clrPosition="top-right" clrSize="xs" *clrIfOpen>
|
||||||
|
<span>{{'REPLICATION.RULE_DISABLED' | translate}}</span>
|
||||||
|
</clr-tooltip-content>
|
||||||
|
</clr-tooltip>
|
||||||
|
<div *ngSwitchCase="true" ><clr-icon shape="success-standard" class="is-success text-alignment" size="18"></clr-icon> Enabled</div>
|
||||||
|
</div>
|
||||||
|
</clr-dg-cell>
|
||||||
<clr-dg-cell class="min-width">
|
<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 : ''}} : {{p.src_namespaces?.length>0 ? p.src_namespaces[0]: ''}}
|
||||||
<clr-tooltip>
|
<clr-tooltip>
|
||||||
@ -28,7 +40,7 @@
|
|||||||
{{p.src_registry && p.src_registry.id > 0 ? 'pull-based' : 'push-based'}}
|
{{p.src_registry && p.src_registry.id > 0 ? 'pull-based' : 'push-based'}}
|
||||||
</clr-dg-cell>
|
</clr-dg-cell>
|
||||||
<clr-dg-cell class="min-width">
|
<clr-dg-cell class="min-width">
|
||||||
{{p.dest_registry ? p.dest_registry.name : ''}} : {{p.dest_namespace? p.dest_namespace: ''}}
|
{{p.dest_registry ? p.dest_registry.name : ''}} : {{p.dest_namespace? p.dest_namespace: '-'}}
|
||||||
</clr-dg-cell>
|
</clr-dg-cell>
|
||||||
<clr-dg-cell>{{p.trigger ? p.trigger.type : ''}}</clr-dg-cell>
|
<clr-dg-cell>{{p.trigger ? p.trigger.type : ''}}</clr-dg-cell>
|
||||||
<clr-dg-cell>
|
<clr-dg-cell>
|
||||||
|
@ -8,3 +8,6 @@
|
|||||||
.min-width {
|
.min-width {
|
||||||
width: 224px;
|
width: 224px;
|
||||||
}
|
}
|
||||||
|
.status-width {
|
||||||
|
width: 105px;
|
||||||
|
}
|
||||||
|
@ -69,22 +69,21 @@
|
|||||||
<h3 class="modal-title">Tasks</h3>
|
<h3 class="modal-title">Tasks</h3>
|
||||||
<div class="row flex-items-xs-between flex-items-xs-bottom">
|
<div class="row flex-items-xs-between flex-items-xs-bottom">
|
||||||
<div class="action-select">
|
<div class="action-select">
|
||||||
<div class="select filterTag" [hidden]="!isOpenFilterTag">
|
<div class="select filter-tag" [hidden]="!isOpenFilterTag">
|
||||||
<select (change)="selectFilter($event)">
|
<select (change)="selectFilter($event)">
|
||||||
<option value="resourceType">{{'REPLICATION.RESOURCE_TYPE' |translate}}</option>
|
<option value="resource_type">{{'REPLICATION.RESOURCE_TYPE' |translate}}</option>
|
||||||
<option value="resource">{{'REPLICATION.RESOURCE' | translate}}</option>
|
|
||||||
<option value="destination">{{'REPLICATION.DESTINATION' | translate}}</option>
|
|
||||||
<option value="status">{{'REPLICATION.STATUS' | translate}}</option>
|
<option value="status">{{'REPLICATION.STATUS' | translate}}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<hbr-filter [withDivider]="true" (openFlag)="openFilter($event)"
|
<hbr-filter [withDivider]="true" (openFlag)="openFilter($event)"
|
||||||
filterPlaceholder='{{"REPLICATION.FILTER_PLACEHOLDER" | translate}}' (filterEvt)="doSearch($event)"></hbr-filter>
|
filterPlaceholder='{{"REPLICATION.FILTER_PLACEHOLDER" | translate}}'
|
||||||
|
(filterEvt)="doSearch($event)" [currentValue]="searchTask"></hbr-filter>
|
||||||
<span class="refresh-btn">
|
<span class="refresh-btn">
|
||||||
<clr-icon shape="refresh" (click)="refreshTasks()"></clr-icon>
|
<clr-icon shape="refresh" (click)="refreshTasks()"></clr-icon>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<clr-datagrid [(clrDgSelected)]="selectedRow" [clrDgLoading]="loading">
|
<clr-datagrid (clrDgRefresh)="clrLoadTasks($event)" [(clrDgSelected)]="selectedRow" [clrDgLoading]="loading">
|
||||||
<clr-dg-column>{{'REPLICATION.TASK_ID'| translate}}</clr-dg-column>
|
<clr-dg-column>{{'REPLICATION.TASK_ID'| translate}}</clr-dg-column>
|
||||||
<clr-dg-column [clrDgField]="'resource_type'">{{'REPLICATION.RESOURCE_TYPE'
|
<clr-dg-column [clrDgField]="'resource_type'">{{'REPLICATION.RESOURCE_TYPE'
|
||||||
| translate}}</clr-dg-column>
|
| translate}}</clr-dg-column>
|
||||||
@ -92,6 +91,8 @@
|
|||||||
translate}}</clr-dg-column>
|
translate}}</clr-dg-column>
|
||||||
<clr-dg-column [clrDgField]="'dst_resource'">{{'REPLICATION.DESTINATION' |
|
<clr-dg-column [clrDgField]="'dst_resource'">{{'REPLICATION.DESTINATION' |
|
||||||
translate}}</clr-dg-column>
|
translate}}</clr-dg-column>
|
||||||
|
<clr-dg-column [clrDgField]="'operation'">{{'REPLICATION.OPERATION' |
|
||||||
|
translate}}</clr-dg-column>
|
||||||
<clr-dg-column [clrDgField]="'status'">{{'REPLICATION.STATUS' |
|
<clr-dg-column [clrDgField]="'status'">{{'REPLICATION.STATUS' |
|
||||||
translate}}</clr-dg-column>
|
translate}}</clr-dg-column>
|
||||||
<clr-dg-column [clrDgSortBy]="startTimeComparator">{{'REPLICATION.CREATION_TIME'
|
<clr-dg-column [clrDgSortBy]="startTimeComparator">{{'REPLICATION.CREATION_TIME'
|
||||||
@ -104,6 +105,7 @@
|
|||||||
<clr-dg-cell>{{t.resource_type}}</clr-dg-cell>
|
<clr-dg-cell>{{t.resource_type}}</clr-dg-cell>
|
||||||
<clr-dg-cell>{{t.src_resource}}</clr-dg-cell>
|
<clr-dg-cell>{{t.src_resource}}</clr-dg-cell>
|
||||||
<clr-dg-cell>{{t.dst_resource}}</clr-dg-cell>
|
<clr-dg-cell>{{t.dst_resource}}</clr-dg-cell>
|
||||||
|
<clr-dg-cell>{{t.operation}}</clr-dg-cell>
|
||||||
<clr-dg-cell>{{t.status}}</clr-dg-cell>
|
<clr-dg-cell>{{t.status}}</clr-dg-cell>
|
||||||
<clr-dg-cell>{{t.start_time | date: 'short'}}</clr-dg-cell>
|
<clr-dg-cell>{{t.start_time | date: 'short'}}</clr-dg-cell>
|
||||||
<clr-dg-cell>{{t.end_time | date: 'short'}}</clr-dg-cell>
|
<clr-dg-cell>{{t.end_time | date: 'short'}}</clr-dg-cell>
|
||||||
@ -123,7 +125,7 @@
|
|||||||
{{pagination.lastItem +1 }} {{'ROBOT_ACCOUNT.OF' |
|
{{pagination.lastItem +1 }} {{'ROBOT_ACCOUNT.OF' |
|
||||||
translate}} </span>
|
translate}} </span>
|
||||||
{{pagination.totalItems }} {{'ROBOT_ACCOUNT.ITEMS' | translate}}
|
{{pagination.totalItems }} {{'ROBOT_ACCOUNT.ITEMS' | translate}}
|
||||||
<clr-dg-pagination #pagination [clrDgPageSize]="15"></clr-dg-pagination>
|
<clr-dg-pagination #pagination [clrDgPageSize]="pageSize" [(clrDgPage)]="currentPage" [clrDgTotalItems]="totalCount"></clr-dg-pagination>
|
||||||
</clr-dg-footer>
|
</clr-dg-footer>
|
||||||
</clr-datagrid>
|
</clr-datagrid>
|
||||||
</div>
|
</div>
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
>div:first-child {
|
>div:first-child {
|
||||||
width: 210px;
|
width: 250px;
|
||||||
}
|
}
|
||||||
>div:nth-child(2) {
|
>div:nth-child(2) {
|
||||||
width: 140px;
|
width: 140px;
|
||||||
@ -72,7 +72,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
|
|
||||||
.filterTag {
|
.filter-tag {
|
||||||
float: left;
|
float: left;
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
}
|
}
|
||||||
@ -85,5 +85,8 @@
|
|||||||
color: #007CBB;
|
color: #007CBB;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
clr-datagrid {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,9 @@ import { ReplicationService } from "../../service/replication.service";
|
|||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { finalize } from "rxjs/operators";
|
import { finalize } from "rxjs/operators";
|
||||||
import { ErrorHandler } from "../../error-handler/error-handler";
|
import { ErrorHandler } from "../../error-handler/error-handler";
|
||||||
import { ReplicationJob, ReplicationTasks, Comparator, ReplicationJobItem } from "../../service/interface";
|
import { ReplicationJob, ReplicationTasks, Comparator, ReplicationJobItem, State } from "../../service/interface";
|
||||||
import { CustomComparator } from "../../utils";
|
import { CustomComparator, DEFAULT_PAGE_SIZE, calculatePage, doFiltering, doSorting } from "../../utils";
|
||||||
|
import { RequestQueryParams } from "../../service/RequestQueryParams";
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'replication-tasks',
|
selector: 'replication-tasks',
|
||||||
templateUrl: './replication-tasks.component.html',
|
templateUrl: './replication-tasks.component.html',
|
||||||
@ -14,10 +15,16 @@ import { CustomComparator } from "../../utils";
|
|||||||
export class ReplicationTasksComponent implements OnInit {
|
export class ReplicationTasksComponent implements OnInit {
|
||||||
isOpenFilterTag: boolean;
|
isOpenFilterTag: boolean;
|
||||||
selectedRow: [];
|
selectedRow: [];
|
||||||
loading = false;
|
currentPage: number = 1;
|
||||||
|
currentPagePvt: number = 0;
|
||||||
|
totalCount: number = 0;
|
||||||
|
pageSize: number = DEFAULT_PAGE_SIZE;
|
||||||
|
currentState: State;
|
||||||
|
loading = true;
|
||||||
searchTask: string;
|
searchTask: string;
|
||||||
defaultFilter = "resourceType";
|
defaultFilter = "resource_type";
|
||||||
tasks: ReplicationTasks[] = [];
|
tasks: ReplicationTasks;
|
||||||
|
taskItem: ReplicationTasks[] = [];
|
||||||
tasksCopy: ReplicationTasks[] = [];
|
tasksCopy: ReplicationTasks[] = [];
|
||||||
stopOnGoing: boolean;
|
stopOnGoing: boolean;
|
||||||
executions: ReplicationJobItem[];
|
executions: ReplicationJobItem[];
|
||||||
@ -37,7 +44,6 @@ export class ReplicationTasksComponent implements OnInit {
|
|||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.clrLoadTasks();
|
|
||||||
this.searchTask = '';
|
this.searchTask = '';
|
||||||
this.getExecutionDetail();
|
this.getExecutionDetail();
|
||||||
}
|
}
|
||||||
@ -97,34 +103,49 @@ export class ReplicationTasksComponent implements OnInit {
|
|||||||
return this.replicationService.getJobBaseUrl() + "/executions/" + this.executionId + "/tasks/" + taskId + "/log";
|
return this.replicationService.getJobBaseUrl() + "/executions/" + this.executionId + "/tasks/" + taskId + "/log";
|
||||||
}
|
}
|
||||||
|
|
||||||
clrLoadTasks(): void {
|
clrLoadTasks(state: State): void {
|
||||||
this.loading = true;
|
|
||||||
this.replicationService.getReplicationTasks(this.executionId)
|
if (!state || !state.page) {
|
||||||
.pipe(finalize(() => (this.loading = false)))
|
return;
|
||||||
.subscribe(tasks => {
|
}
|
||||||
if (this.defaultFilter === 'resourceType') {
|
// Keep it for future filter
|
||||||
this.tasks = tasks.filter(x =>
|
this.currentState = state;
|
||||||
x.resource_type.includes(this.searchTask)
|
|
||||||
);
|
let pageNumber: number = calculatePage(state);
|
||||||
} else if (this.defaultFilter === 'resource') {
|
if (pageNumber !== this.currentPagePvt) {
|
||||||
this.tasks = tasks.filter(x =>
|
// load data
|
||||||
x.src_resource.includes(this.searchTask)
|
let params: RequestQueryParams = new RequestQueryParams();
|
||||||
);
|
params.set("page", '' + pageNumber);
|
||||||
} else if (this.defaultFilter === 'destination') {
|
params.set("page_size", '' + this.pageSize);
|
||||||
this.tasks = tasks.filter(x =>
|
if (this.searchTask && this.searchTask !== "") {
|
||||||
x.dst_resource.includes(this.searchTask)
|
params.set(this.defaultFilter, this.searchTask);
|
||||||
);
|
|
||||||
} else {
|
|
||||||
this.tasks = tasks.filter(x =>
|
|
||||||
x.status.includes(this.searchTask)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.tasksCopy = tasks.map(x => Object.assign({}, x));
|
this.loading = true;
|
||||||
|
this.replicationService.getReplicationTasks(this.executionId, params)
|
||||||
|
.pipe(finalize(() => (this.loading = false)))
|
||||||
|
.subscribe(res => {
|
||||||
|
this.totalCount = res.length;
|
||||||
|
this.tasks = res; // Keep the data
|
||||||
|
this.taskItem = this.tasks.filter(tasks => tasks.resource_type !== "");
|
||||||
|
this.taskItem = doFiltering<ReplicationTasks>(this.taskItem, state);
|
||||||
|
|
||||||
|
this.taskItem = doSorting<ReplicationTasks>(this.taskItem, state);
|
||||||
|
|
||||||
|
this.currentPagePvt = pageNumber;
|
||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
this.errorHandler.error(error);
|
this.errorHandler.error(error);
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
|
||||||
|
this.taskItem = this.tasks.filter(tasks => tasks.resource_type !== "");
|
||||||
|
// Do customized filter
|
||||||
|
this.taskItem = doFiltering<ReplicationTasks>(this.taskItem, state);
|
||||||
|
|
||||||
|
// Do customized sorting
|
||||||
|
this.taskItem = doSorting<ReplicationTasks>(this.taskItem, state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
onBack(): void {
|
onBack(): void {
|
||||||
this.router.navigate(["harbor", "replications"]);
|
this.router.navigate(["harbor", "replications"]);
|
||||||
@ -138,15 +159,41 @@ export class ReplicationTasksComponent implements OnInit {
|
|||||||
// refresh icon
|
// refresh icon
|
||||||
refreshTasks(): void {
|
refreshTasks(): void {
|
||||||
this.searchTask = '';
|
this.searchTask = '';
|
||||||
this.clrLoadTasks();
|
this.loading = true;
|
||||||
|
this.replicationService.getReplicationTasks(this.executionId)
|
||||||
|
.subscribe(res => {
|
||||||
|
this.tasks = res;
|
||||||
|
this.loading = false;
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
this.loading = false;
|
||||||
|
this.errorHandler.error(error);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
doSearch(value: string): void {
|
public doSearch(value: string): void {
|
||||||
if (!value) {
|
if (!value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.searchTask = value.trim();
|
this.searchTask = value.trim();
|
||||||
this.clrLoadTasks();
|
this.loading = true;
|
||||||
|
this.currentPage = 1;
|
||||||
|
if (this.currentPagePvt === 1) {
|
||||||
|
// Force reloading
|
||||||
|
let st: State = this.currentState;
|
||||||
|
if (!st) {
|
||||||
|
st = {
|
||||||
|
page: {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
st.page.from = 0;
|
||||||
|
st.page.to = this.pageSize - 1;
|
||||||
|
st.page.size = this.pageSize;
|
||||||
|
|
||||||
|
this.currentPagePvt = 0;
|
||||||
|
|
||||||
|
this.clrLoadTasks(st);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
openFilter(isOpen: boolean): void {
|
openFilter(isOpen: boolean): void {
|
||||||
|
@ -24,19 +24,21 @@
|
|||||||
<div *ngIf="withReplicationJob" class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
|
<div *ngIf="withReplicationJob" class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
|
||||||
<div class="row flex-items-xs-between jobsRow">
|
<div class="row flex-items-xs-between jobsRow">
|
||||||
<h5 class="flex-items-xs-bottom option-left-down">{{'REPLICATION.REPLICATION_EXECUTIONS' | translate}}</h5>
|
<h5 class="flex-items-xs-bottom option-left-down">{{'REPLICATION.REPLICATION_EXECUTIONS' | translate}}</h5>
|
||||||
<div class="flex-items-xs-bottom option-right-down">
|
<div class="row flex-items-xs-between flex-items-xs-bottom">
|
||||||
<button class="btn btn-link" (click)="toggleSearchJobOptionalName(currentJobSearchOption)">{{"REPLICATION.ADVANCED" | translate}}</button>
|
<div class="execution-select">
|
||||||
</div>
|
<div class="select filter-tag" [hidden]="!isOpenFilterTag">
|
||||||
</div>
|
<select (change)="doFilterJob($event)">
|
||||||
<div class="row flex-items-xs-right row-right" [hidden]="currentJobSearchOption === 0">
|
<option value="trigger">{{'REPLICATION.REPLICATION_TRIGGER' |translate}}</option>
|
||||||
<div class="select select-status">
|
<option value="status">{{'REPLICATION.STATUS' | translate}}</option>
|
||||||
<select (change)="doFilterJobStatus($event)">
|
</select>
|
||||||
<option *ngFor="let j of jobStatus" value="{{j.key}}" [selected]="currentJobStatus.key === j.key">{{j.description | translate}}</option>
|
</div>
|
||||||
</select>
|
<hbr-filter [withDivider]="true" (openFlag)="openFilter($event)"
|
||||||
</div>
|
filterPlaceholder='{{"REPLICATION.FILTER_EXECUTIONS_PLACEHOLDER" | translate}}'
|
||||||
<div class="flex-items-xs-middle">
|
(filterEvt)="doSearchExecutions($event)" [currentValue]="currentTerm"></hbr-filter>
|
||||||
<hbr-datetime [dateInput]="search.startTime" (search)="doJobSearchByStartTime($event)"></hbr-datetime>
|
<span class="refresh-btn">
|
||||||
<hbr-datetime [dateInput]="search.endTime" [oneDayOffset]="true" (search)="doJobSearchByEndTime($event)"></hbr-datetime>
|
<clr-icon shape="refresh" (click)="refreshJobs()"></clr-icon>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -61,11 +63,19 @@
|
|||||||
</clr-dg-cell>
|
</clr-dg-cell>
|
||||||
<clr-dg-cell>{{j.trigger}}</clr-dg-cell>
|
<clr-dg-cell>{{j.trigger}}</clr-dg-cell>
|
||||||
<clr-dg-cell>{{j.start_time | date: 'short'}}</clr-dg-cell>
|
<clr-dg-cell>{{j.start_time | date: 'short'}}</clr-dg-cell>
|
||||||
<clr-dg-cell>{{'3mins'}}</clr-dg-cell>
|
<clr-dg-cell>{{getDuration(j)}}</clr-dg-cell>
|
||||||
<clr-dg-cell>
|
<clr-dg-cell>
|
||||||
{{'90%'}}
|
{{(j.succeed > 0 ? j.succeed / j.total : 0) | percent }}
|
||||||
|
</clr-dg-cell>
|
||||||
|
<clr-dg-cell>
|
||||||
|
{{j.status}}
|
||||||
|
<clr-tooltip>
|
||||||
|
<clr-icon *ngIf="j.status_text" clrTooltipTrigger shape="info-circle" size="20"></clr-icon>
|
||||||
|
<clr-tooltip-content [clrPosition]="'left'" clrSize="md" *clrIfOpen>
|
||||||
|
<span>{{j.status_text}}</span>
|
||||||
|
</clr-tooltip-content>
|
||||||
|
</clr-tooltip>
|
||||||
</clr-dg-cell>
|
</clr-dg-cell>
|
||||||
<clr-dg-cell>{{j.status}}</clr-dg-cell>
|
|
||||||
</clr-dg-row>
|
</clr-dg-row>
|
||||||
<clr-dg-footer>
|
<clr-dg-footer>
|
||||||
<span *ngIf="showPaginationIndex">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'REPLICATION.OF' | translate}}</span>
|
<span *ngIf="showPaginationIndex">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'REPLICATION.OF' | translate}}</span>
|
||||||
|
@ -13,6 +13,25 @@
|
|||||||
padding-right: 16px;
|
padding-right: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.execution-select {
|
||||||
|
padding-right: 18px;
|
||||||
|
height: 24px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
padding-top: 25px;
|
||||||
|
.filter-tag {
|
||||||
|
float: left;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
.refresh-btn {
|
||||||
|
cursor: pointer;
|
||||||
|
margin-top: 7px;
|
||||||
|
&:hover {
|
||||||
|
color: #007CBB;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.rightPos{
|
.rightPos{
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 35px;
|
right: 35px;
|
||||||
@ -49,3 +68,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clr-datagrid {
|
||||||
|
::ng-deep .datagrid-table {
|
||||||
|
position: static;
|
||||||
|
}
|
||||||
|
}
|
@ -262,7 +262,6 @@ describe('Replication Component (inline template)', () => {
|
|||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
fixture.whenStable().then(() => {
|
fixture.whenStable().then(() => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
comp.doFilterJobStatus('finished');
|
|
||||||
let el: HTMLElement = deJobs.nativeElement;
|
let el: HTMLElement = deJobs.nativeElement;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(el).toBeTruthy();
|
expect(el).toBeTruthy();
|
||||||
@ -274,8 +273,6 @@ describe('Replication Component (inline template)', () => {
|
|||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
fixture.whenStable().then(() => {
|
fixture.whenStable().then(() => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
comp.doJobSearchByStartTime('2017-05-01');
|
|
||||||
comp.doJobSearchByEndTime('2015-05-25');
|
|
||||||
let el: HTMLElement = deJobs.nativeElement;
|
let el: HTMLElement = deJobs.nativeElement;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(el).toBeTruthy();
|
expect(el).toBeTruthy();
|
||||||
|
@ -53,9 +53,16 @@ import {
|
|||||||
import { ConfirmationMessage } from "../confirmation-dialog/confirmation-message";
|
import { ConfirmationMessage } from "../confirmation-dialog/confirmation-message";
|
||||||
import { ConfirmationDialogComponent } from "../confirmation-dialog/confirmation-dialog.component";
|
import { ConfirmationDialogComponent } from "../confirmation-dialog/confirmation-dialog.component";
|
||||||
import { ConfirmationAcknowledgement } from "../confirmation-dialog/confirmation-state-message";
|
import { ConfirmationAcknowledgement } from "../confirmation-dialog/confirmation-state-message";
|
||||||
import { operateChanges, OperationState, OperateInfo } from "../operation/operate";
|
import {
|
||||||
|
operateChanges,
|
||||||
|
OperationState,
|
||||||
|
OperateInfo
|
||||||
|
} from "../operation/operate";
|
||||||
import { OperationService } from "../operation/operation.service";
|
import { OperationService } from "../operation/operation.service";
|
||||||
import { Router } from "@angular/router";
|
import { Router } from "@angular/router";
|
||||||
|
const ONE_HOUR_SECONDS: number = 3600;
|
||||||
|
const ONE_MINUTE_SECONDS: number = 60;
|
||||||
|
const ONE_DAY_SECONDS: number = 24 * ONE_HOUR_SECONDS;
|
||||||
|
|
||||||
const ruleStatus: { [key: string]: any } = [
|
const ruleStatus: { [key: string]: any } = [
|
||||||
{ key: "all", description: "REPLICATION.ALL_STATUS" },
|
{ key: "all", description: "REPLICATION.ALL_STATUS" },
|
||||||
@ -63,26 +70,11 @@ const ruleStatus: { [key: string]: any } = [
|
|||||||
{ key: "0", description: "REPLICATION.DISABLED" }
|
{ key: "0", description: "REPLICATION.DISABLED" }
|
||||||
];
|
];
|
||||||
|
|
||||||
const jobStatus: { [key: string]: any } = [
|
|
||||||
{ key: "all", description: "REPLICATION.ALL" },
|
|
||||||
{ key: "pending", description: "REPLICATION.PENDING" },
|
|
||||||
{ key: "running", description: "REPLICATION.RUNNING" },
|
|
||||||
{ key: "error", description: "REPLICATION.ERROR" },
|
|
||||||
{ key: "retrying", description: "REPLICATION.RETRYING" },
|
|
||||||
{ key: "stopped", description: "REPLICATION.STOPPED" },
|
|
||||||
{ key: "finished", description: "REPLICATION.FINISHED" },
|
|
||||||
{ key: "canceled", description: "REPLICATION.CANCELED" }
|
|
||||||
];
|
|
||||||
|
|
||||||
export class SearchOption {
|
export class SearchOption {
|
||||||
ruleId: number | string;
|
ruleId: number | string;
|
||||||
ruleName: string = "";
|
ruleName: string = "";
|
||||||
repoName: string = "";
|
trigger: string = "";
|
||||||
status: string = "";
|
status: string = "";
|
||||||
startTime: string = "";
|
|
||||||
startTimestamp: string = "";
|
|
||||||
endTime: string = "";
|
|
||||||
endTimestamp: string = "";
|
|
||||||
page: number = 1;
|
page: number = 1;
|
||||||
pageSize: number = DEFAULT_PAGE_SIZE;
|
pageSize: number = DEFAULT_PAGE_SIZE;
|
||||||
}
|
}
|
||||||
@ -109,12 +101,12 @@ export class ReplicationComponent implements OnInit, OnDestroy {
|
|||||||
@Output() goToRegistry = new EventEmitter<any>();
|
@Output() goToRegistry = new EventEmitter<any>();
|
||||||
|
|
||||||
search: SearchOption = new SearchOption();
|
search: SearchOption = new SearchOption();
|
||||||
|
isOpenFilterTag: boolean;
|
||||||
ruleStatus = ruleStatus;
|
ruleStatus = ruleStatus;
|
||||||
currentRuleStatus: { key: string; description: string };
|
currentRuleStatus: { key: string; description: string };
|
||||||
|
|
||||||
jobStatus = jobStatus;
|
currentTerm: string;
|
||||||
currentJobStatus: { key: string; description: string };
|
defaultFilter = "trigger";
|
||||||
|
|
||||||
changedRules: ReplicationRule[];
|
changedRules: ReplicationRule[];
|
||||||
|
|
||||||
@ -125,7 +117,6 @@ export class ReplicationComponent implements OnInit, OnDestroy {
|
|||||||
hiddenJobList = true;
|
hiddenJobList = true;
|
||||||
|
|
||||||
jobs: ReplicationJobItem[];
|
jobs: ReplicationJobItem[];
|
||||||
currentJobSearchOption: number;
|
|
||||||
|
|
||||||
@ViewChild(ListReplicationRuleComponent)
|
@ViewChild(ListReplicationRuleComponent)
|
||||||
listReplicationRule: ListReplicationRuleComponent;
|
listReplicationRule: ListReplicationRuleComponent;
|
||||||
@ -133,7 +124,6 @@ export class ReplicationComponent implements OnInit, OnDestroy {
|
|||||||
@ViewChild(CreateEditRuleComponent)
|
@ViewChild(CreateEditRuleComponent)
|
||||||
createEditPolicyComponent: CreateEditRuleComponent;
|
createEditPolicyComponent: CreateEditRuleComponent;
|
||||||
|
|
||||||
|
|
||||||
@ViewChild("replicationConfirmDialog")
|
@ViewChild("replicationConfirmDialog")
|
||||||
replicationConfirmDialog: ConfirmationDialogComponent;
|
replicationConfirmDialog: ConfirmationDialogComponent;
|
||||||
|
|
||||||
@ -142,10 +132,10 @@ export class ReplicationComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
creationTimeComparator: Comparator<ReplicationJob> = new CustomComparator<
|
creationTimeComparator: Comparator<ReplicationJob> = new CustomComparator<
|
||||||
ReplicationJob
|
ReplicationJob
|
||||||
>("start_time", "date");
|
>("start_time", "date");
|
||||||
updateTimeComparator: Comparator<ReplicationJob> = new CustomComparator<
|
updateTimeComparator: Comparator<ReplicationJob> = new CustomComparator<
|
||||||
ReplicationJob
|
ReplicationJob
|
||||||
>("end_time", "date");
|
>("end_time", "date");
|
||||||
|
|
||||||
// Server driven pagination
|
// Server driven pagination
|
||||||
currentPage: number = 1;
|
currentPage: number = 1;
|
||||||
@ -160,7 +150,8 @@ export class ReplicationComponent implements OnInit, OnDestroy {
|
|||||||
private errorHandler: ErrorHandler,
|
private errorHandler: ErrorHandler,
|
||||||
private replicationService: ReplicationService,
|
private replicationService: ReplicationService,
|
||||||
private operationService: OperationService,
|
private operationService: OperationService,
|
||||||
private translateService: TranslateService) { }
|
private translateService: TranslateService
|
||||||
|
) {}
|
||||||
|
|
||||||
public get showPaginationIndex(): boolean {
|
public get showPaginationIndex(): boolean {
|
||||||
return this.totalCount > 0;
|
return this.totalCount > 0;
|
||||||
@ -168,8 +159,6 @@ export class ReplicationComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.currentRuleStatus = this.ruleStatus[0];
|
this.currentRuleStatus = this.ruleStatus[0];
|
||||||
this.currentJobStatus = this.jobStatus[0];
|
|
||||||
this.currentJobSearchOption = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
@ -215,43 +204,23 @@ export class ReplicationComponent implements OnInit, OnDestroy {
|
|||||||
// Pagination
|
// Pagination
|
||||||
params.set("page", "" + pageNumber);
|
params.set("page", "" + pageNumber);
|
||||||
params.set("page_size", "" + this.pageSize);
|
params.set("page_size", "" + this.pageSize);
|
||||||
// Search by status
|
|
||||||
if (this.search.status.trim()) {
|
if (this.currentTerm && this.currentTerm !== "") {
|
||||||
params.set("status", this.search.status);
|
params.set(this.defaultFilter, this.currentTerm);
|
||||||
}
|
|
||||||
// Search by repository
|
|
||||||
if (this.search.repoName.trim()) {
|
|
||||||
params.set("repository", this.search.repoName);
|
|
||||||
}
|
|
||||||
// Search by timestamps
|
|
||||||
if (this.search.startTimestamp.trim()) {
|
|
||||||
params.set("start_time", this.search.startTimestamp);
|
|
||||||
}
|
|
||||||
if (this.search.endTimestamp.trim()) {
|
|
||||||
params.set("end_time", this.search.endTimestamp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.jobsLoading = true;
|
this.jobsLoading = true;
|
||||||
|
|
||||||
// Do filtering and sorting
|
this.replicationService.getExecutions(this.search.ruleId, params).subscribe(
|
||||||
this.jobs = doFiltering<ReplicationJobItem>(this.jobs, state);
|
response => {
|
||||||
this.jobs = doSorting<ReplicationJobItem>(this.jobs, state);
|
|
||||||
|
|
||||||
this.jobsLoading = false;
|
|
||||||
|
|
||||||
this.replicationService.getExecutions(this.search.ruleId, params)
|
|
||||||
.subscribe(response => {
|
|
||||||
this.totalCount = response.metadata.xTotalCount;
|
this.totalCount = response.metadata.xTotalCount;
|
||||||
this.jobs = response.data;
|
this.jobs = response.data;
|
||||||
|
|
||||||
if (!this.timerDelay) {
|
if (!this.timerDelay) {
|
||||||
this.timerDelay = timer(10000, 10000).subscribe(() => {
|
this.timerDelay = timer(10000, 10000).subscribe(() => {
|
||||||
let count: number = 0;
|
let count: number = 0;
|
||||||
this.jobs.forEach(job => {
|
this.jobs.forEach(job => {
|
||||||
if (
|
if (
|
||||||
job.status === "pending" ||
|
job.status === "InProgress"
|
||||||
job.status === "running" ||
|
|
||||||
job.status === "retrying"
|
|
||||||
) {
|
) {
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
@ -264,18 +233,30 @@ export class ReplicationComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do filtering and sorting
|
// Do filtering and sorting
|
||||||
this.jobs = doFiltering<ReplicationJobItem>(this.jobs, state);
|
this.jobs = doFiltering<ReplicationJobItem>(this.jobs, state);
|
||||||
this.jobs = doSorting<ReplicationJobItem>(this.jobs, state);
|
this.jobs = doSorting<ReplicationJobItem>(this.jobs, state);
|
||||||
|
|
||||||
this.jobsLoading = false;
|
this.jobsLoading = false;
|
||||||
}, error => {
|
},
|
||||||
|
error => {
|
||||||
this.jobsLoading = false;
|
this.jobsLoading = false;
|
||||||
this.errorHandler.error(error);
|
this.errorHandler.error(error);
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
public doSearchExecutions(terms: string): void {
|
||||||
|
if (!terms) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.currentTerm = terms.trim();
|
||||||
|
// Trigger data loading and start from first page
|
||||||
|
this.jobsLoading = true;
|
||||||
|
this.currentPage = 1;
|
||||||
|
this.jobsLoading = true;
|
||||||
|
// Force reloading
|
||||||
|
this.loadFirstPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
loadFirstPage(): void {
|
loadFirstPage(): void {
|
||||||
let st: State = this.currentState;
|
let st: State = this.currentState;
|
||||||
if (!st) {
|
if (!st) {
|
||||||
@ -294,10 +275,6 @@ export class ReplicationComponent implements OnInit, OnDestroy {
|
|||||||
if (rule && rule.id) {
|
if (rule && rule.id) {
|
||||||
this.hiddenJobList = false;
|
this.hiddenJobList = false;
|
||||||
this.search.ruleId = rule.id || "";
|
this.search.ruleId = rule.id || "";
|
||||||
this.search.repoName = "";
|
|
||||||
this.search.status = "";
|
|
||||||
this.currentJobSearchOption = 0;
|
|
||||||
this.currentJobStatus = { key: "all", description: "REPLICATION.ALL" };
|
|
||||||
this.loadFirstPage();
|
this.loadFirstPage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -325,7 +302,7 @@ export class ReplicationComponent implements OnInit, OnDestroy {
|
|||||||
let rule: ReplicationRule = message.data;
|
let rule: ReplicationRule = message.data;
|
||||||
|
|
||||||
if (rule) {
|
if (rule) {
|
||||||
forkJoin(this.replicationOperate(rule)).subscribe((item) => {
|
forkJoin(this.replicationOperate(rule)).subscribe(item => {
|
||||||
this.selectOneRule(rule);
|
this.selectOneRule(rule);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -335,30 +312,39 @@ export class ReplicationComponent implements OnInit, OnDestroy {
|
|||||||
replicationOperate(rule: ReplicationRule): Observable<any> {
|
replicationOperate(rule: ReplicationRule): Observable<any> {
|
||||||
// init operation info
|
// init operation info
|
||||||
let operMessage = new OperateInfo();
|
let operMessage = new OperateInfo();
|
||||||
operMessage.name = 'OPERATION.REPLICATION';
|
operMessage.name = "OPERATION.REPLICATION";
|
||||||
operMessage.data.id = rule.id;
|
operMessage.data.id = rule.id;
|
||||||
operMessage.state = OperationState.progressing;
|
operMessage.state = OperationState.progressing;
|
||||||
operMessage.data.name = rule.name;
|
operMessage.data.name = rule.name;
|
||||||
this.operationService.publishInfo(operMessage);
|
this.operationService.publishInfo(operMessage);
|
||||||
|
|
||||||
return this.replicationService.replicateRule(+rule.id)
|
return this.replicationService.replicateRule(+rule.id).pipe(
|
||||||
.pipe(map(response => {
|
map(response => {
|
||||||
this.translateService.get('BATCH.REPLICATE_SUCCESS')
|
this.translateService
|
||||||
.subscribe(res => operateChanges(operMessage, OperationState.success));
|
.get("BATCH.REPLICATE_SUCCESS")
|
||||||
})
|
.subscribe(res =>
|
||||||
, catchError(error => {
|
operateChanges(operMessage, OperationState.success)
|
||||||
if (error && error.status === 412) {
|
);
|
||||||
return forkJoin(this.translateService.get('BATCH.REPLICATE_FAILURE'),
|
}),
|
||||||
this.translateService.get('REPLICATION.REPLICATE_SUMMARY_FAILURE'))
|
catchError(error => {
|
||||||
.pipe(map(function (res) {
|
if (error && error.status === 412) {
|
||||||
operateChanges(operMessage, OperationState.failure, res[1]);
|
return forkJoin(
|
||||||
}));
|
this.translateService.get("BATCH.REPLICATE_FAILURE"),
|
||||||
} else {
|
this.translateService.get("REPLICATION.REPLICATE_SUMMARY_FAILURE")
|
||||||
return this.translateService.get('BATCH.REPLICATE_FAILURE').pipe(map(res => {
|
).pipe(
|
||||||
|
map(function(res) {
|
||||||
|
operateChanges(operMessage, OperationState.failure, res[1]);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return this.translateService.get("BATCH.REPLICATE_FAILURE").pipe(
|
||||||
|
map(res => {
|
||||||
operateChanges(operMessage, OperationState.failure, res);
|
operateChanges(operMessage, OperationState.failure, res);
|
||||||
}));
|
})
|
||||||
}
|
);
|
||||||
}));
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
customRedirect(rule: ReplicationRule) {
|
customRedirect(rule: ReplicationRule) {
|
||||||
@ -370,21 +356,17 @@ export class ReplicationComponent implements OnInit, OnDestroy {
|
|||||||
this.listReplicationRule.retrieveRules(ruleName);
|
this.listReplicationRule.retrieveRules(ruleName);
|
||||||
}
|
}
|
||||||
|
|
||||||
doFilterJobStatus($event: any) {
|
doFilterJob($event: any): void {
|
||||||
if ($event && $event.target && $event.target["value"]) {
|
this.defaultFilter = $event["target"].value;
|
||||||
let status = $event.target["value"];
|
this.doSearchJobs(this.currentTerm);
|
||||||
|
|
||||||
this.currentJobStatus = this.jobStatus.find((r: any) => r.key === status);
|
|
||||||
if (this.currentJobStatus.key === "all") {
|
|
||||||
status = "";
|
|
||||||
}
|
|
||||||
this.search.status = status;
|
|
||||||
this.doSearchJobs(this.search.repoName);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
doSearchJobs(repoName: string) {
|
doSearchJobs(terms: string) {
|
||||||
this.search.repoName = repoName;
|
if (!terms) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.currentTerm = terms.trim();
|
||||||
|
this.currentPage = 1;
|
||||||
this.loadFirstPage();
|
this.loadFirstPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -434,7 +416,7 @@ export class ReplicationComponent implements OnInit, OnDestroy {
|
|||||||
this.selectedRow = [];
|
this.selectedRow = [];
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.subscribe(() => { });
|
.subscribe(() => {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -468,14 +450,7 @@ export class ReplicationComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
refreshJobs() {
|
refreshJobs() {
|
||||||
this.currentJobStatus = this.jobStatus[0];
|
this.currentTerm = "";
|
||||||
this.search.startTime = " ";
|
|
||||||
this.search.endTime = " ";
|
|
||||||
this.search.repoName = "";
|
|
||||||
this.search.startTimestamp = "";
|
|
||||||
this.search.endTimestamp = "";
|
|
||||||
this.search.status = "";
|
|
||||||
|
|
||||||
this.currentPage = 1;
|
this.currentPage = 1;
|
||||||
|
|
||||||
let st: State = {
|
let st: State = {
|
||||||
@ -488,19 +463,36 @@ export class ReplicationComponent implements OnInit, OnDestroy {
|
|||||||
this.clrLoadJobs(st);
|
this.clrLoadJobs(st);
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleSearchJobOptionalName(option: number) {
|
openFilter(isOpen: boolean): void {
|
||||||
option === 1
|
if (isOpen) {
|
||||||
? (this.currentJobSearchOption = 0)
|
this.isOpenFilterTag = true;
|
||||||
: (this.currentJobSearchOption = 1);
|
} else {
|
||||||
|
this.isOpenFilterTag = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
getDuration(j: ReplicationJobItem) {
|
||||||
|
if (!j) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (j.status === "Failed") {
|
||||||
|
return "-";
|
||||||
|
}
|
||||||
|
let start_time = new Date(j.start_time).getTime();
|
||||||
|
let end_time = new Date(j.end_time).getTime();
|
||||||
|
let timesDiff = end_time - start_time;
|
||||||
|
let timesDiffSeconds = timesDiff / 1000;
|
||||||
|
let minutes = Math.floor(((timesDiffSeconds % ONE_DAY_SECONDS) % ONE_HOUR_SECONDS) / ONE_MINUTE_SECONDS);
|
||||||
|
let seconds = Math.floor(timesDiffSeconds % ONE_MINUTE_SECONDS);
|
||||||
|
if (minutes > 0) {
|
||||||
|
return minutes + "m" + seconds + "s";
|
||||||
|
}
|
||||||
|
|
||||||
doJobSearchByStartTime(fromTimestamp: string) {
|
if (seconds > 0) {
|
||||||
this.search.startTimestamp = fromTimestamp;
|
return seconds + "s";
|
||||||
this.loadFirstPage();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
doJobSearchByEndTime(toTimestamp: string) {
|
if (seconds <= 0 && timesDiff > 0) {
|
||||||
this.search.endTimestamp = toTimestamp;
|
return timesDiff + 'ms';
|
||||||
this.loadFirstPage();
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -175,6 +175,7 @@ export interface ReplicationJobItem extends Base {
|
|||||||
*/
|
*/
|
||||||
export interface ReplicationTasks extends Base {
|
export interface ReplicationTasks extends Base {
|
||||||
[key: string]: any | any[];
|
[key: string]: any | any[];
|
||||||
|
operation: string;
|
||||||
id: number;
|
id: number;
|
||||||
execution_id: number;
|
execution_id: number;
|
||||||
resource_type: string;
|
resource_type: string;
|
||||||
|
@ -67,7 +67,8 @@ export abstract class ReplicationService {
|
|||||||
* @memberOf ReplicationService
|
* @memberOf ReplicationService
|
||||||
*/
|
*/
|
||||||
abstract getReplicationTasks(
|
abstract getReplicationTasks(
|
||||||
executionId: number | string
|
executionId: number | string,
|
||||||
|
queryParams?: RequestQueryParams
|
||||||
): Observable<ReplicationTasks>;
|
): Observable<ReplicationTasks>;
|
||||||
/**
|
/**
|
||||||
* Create new replication rule.
|
* Create new replication rule.
|
||||||
@ -287,14 +288,16 @@ export class ReplicationDefaultService extends ReplicationService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getReplicationTasks(
|
public getReplicationTasks(
|
||||||
executionId: number | string
|
executionId: number | string,
|
||||||
|
queryParams?: RequestQueryParams
|
||||||
): Observable<ReplicationTasks> {
|
): Observable<ReplicationTasks> {
|
||||||
if (!executionId) {
|
if (!executionId) {
|
||||||
return observableThrowError("Bad argument");
|
return observableThrowError("Bad argument");
|
||||||
}
|
}
|
||||||
let url: string = `${this._replicateUrl}/executions/${executionId}/tasks`;
|
let url: string = `${this._replicateUrl}/executions/${executionId}/tasks`;
|
||||||
return this.http
|
return this.http
|
||||||
.get(url, HTTP_GET_OPTIONS)
|
.get(url,
|
||||||
|
queryParams ? buildHttpRequestOptions(queryParams) : HTTP_GET_OPTIONS)
|
||||||
.pipe(map(response => response.json() as ReplicationTasks)
|
.pipe(map(response => response.json() as ReplicationTasks)
|
||||||
, catchError(error => observableThrowError(error)));
|
, catchError(error => observableThrowError(error)));
|
||||||
}
|
}
|
||||||
|
@ -340,6 +340,7 @@
|
|||||||
"OF": "of"
|
"OF": "of"
|
||||||
},
|
},
|
||||||
"REPLICATION": {
|
"REPLICATION": {
|
||||||
|
"OPERATION": "Operation",
|
||||||
"CURRENT": "current",
|
"CURRENT": "current",
|
||||||
"FILTER_PLACEHOLDER": "Filter Tasks",
|
"FILTER_PLACEHOLDER": "Filter Tasks",
|
||||||
"STOP_TITLE": "Confirm Stop Executions",
|
"STOP_TITLE": "Confirm Stop Executions",
|
||||||
|
Loading…
Reference in New Issue
Block a user