mirror of
https://github.com/goharbor/harbor.git
synced 2024-12-28 19:47:58 +01:00
Merge pull request #7224 from pureshine/replication_ng
Refactor replication-task page according to the new design
This commit is contained in:
commit
1491cf1846
@ -42,6 +42,19 @@ import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { of } from "rxjs";
|
||||
|
||||
describe("CreateEditRuleComponent (inline template)", () => {
|
||||
let mockEndpoint: Endpoint = {
|
||||
id: 1,
|
||||
credential: {
|
||||
access_key: "admin",
|
||||
access_secret: "",
|
||||
type: "basic"
|
||||
},
|
||||
description: "test",
|
||||
insecure: false,
|
||||
name: "target_01",
|
||||
type: "Harbor",
|
||||
url: "https://10.117.4.151"
|
||||
};
|
||||
let mockRules: ReplicationRule[] = [
|
||||
{
|
||||
id: 1,
|
||||
@ -205,6 +218,8 @@ describe("CreateEditRuleComponent (inline template)", () => {
|
||||
let spyJobs: jasmine.Spy;
|
||||
let spyAdapter: jasmine.Spy;
|
||||
let spyEndpoint: jasmine.Spy;
|
||||
let spyEndpoints: jasmine.Spy;
|
||||
|
||||
|
||||
let config: IServiceConfig = {
|
||||
replicationBaseEndpoint: "/api/replication/testing",
|
||||
@ -262,10 +277,14 @@ describe("CreateEditRuleComponent (inline template)", () => {
|
||||
|
||||
spyAdapter = spyOn(replicationService, "getReplicationAdapter").and.returnValues(
|
||||
of(mockAdapter));
|
||||
spyEndpoint = spyOn(endpointService, "getEndpoints").and.returnValues(
|
||||
spyEndpoints = spyOn(endpointService, "getEndpoints").and.returnValues(
|
||||
of(mockEndpoints)
|
||||
);
|
||||
|
||||
spyEndpoint = spyOn(endpointService, "getEndpoint").and.returnValue(
|
||||
of(mockEndpoint)
|
||||
);
|
||||
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
|
@ -10,14 +10,13 @@
|
||||
<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.DESTINATION_NAMESPACE' | translate}}</clr-dg-column>
|
||||
<clr-dg-column>{{'REPLICATION.LAST_REPLICATION' | translate}}</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'trigger'">{{'REPLICATION.REPLICATION_TRIGGER' | 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" [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 class="min-width">
|
||||
{{p.src_registry_id>0? srcRegistry : 'current'}} : {{p.src_namespaces?.length>0 ? p.src_namespaces[0]: ''}}
|
||||
{{p.src_registry_id? registryName[i]:'current'}} : {{p.src_namespaces?.length>0 ? p.src_namespaces[0]: ''}}
|
||||
<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>
|
||||
@ -29,9 +28,8 @@
|
||||
{{p.src_registry_id>0? 'pull-based' : 'push-based'}}
|
||||
</clr-dg-cell>
|
||||
<clr-dg-cell class="min-width">
|
||||
{{p.dest_registry_id>0? srcRegistry : 'current'}} : {{p.dest_namespace? p.dest_namespace: ''}}
|
||||
{{p.dest_registry_id? registryName[i]: 'current'}} : {{p.dest_namespace? p.dest_namespace: ''}}
|
||||
</clr-dg-cell>
|
||||
<clr-dg-cell>{{p.update_time | date: 'short'}}</clr-dg-cell>
|
||||
<clr-dg-cell>{{p.trigger ? p.trigger.type : ''}}</clr-dg-cell>
|
||||
<clr-dg-cell>
|
||||
{{p.description ? trancatedDescription(p.description) : '-'}}
|
||||
|
@ -15,8 +15,23 @@ import { SERVICE_CONFIG, IServiceConfig } from '../service.config';
|
||||
import { ReplicationService, ReplicationDefaultService } from '../service/replication.service';
|
||||
import { OperationService } from "../operation/operation.service";
|
||||
import { of } from 'rxjs';
|
||||
import { EndpointService, EndpointDefaultService } from "../service/endpoint.service";
|
||||
import { Endpoint } from "../service/interface";
|
||||
|
||||
describe('ListReplicationRuleComponent (inline template)', () => {
|
||||
let mockEndpoint: Endpoint = {
|
||||
id: 1,
|
||||
credential: {
|
||||
access_key: "admin",
|
||||
access_secret: "",
|
||||
type: "basic"
|
||||
},
|
||||
description: "test",
|
||||
insecure: false,
|
||||
name: "target_01",
|
||||
type: "Harbor",
|
||||
url: "https://10.117.4.151"
|
||||
};
|
||||
|
||||
let mockRules: ReplicationRule[] = [
|
||||
{
|
||||
@ -49,10 +64,16 @@ describe('ListReplicationRuleComponent (inline template)', () => {
|
||||
|
||||
let replicationService: ReplicationService;
|
||||
|
||||
let endpointService: EndpointService;
|
||||
|
||||
|
||||
let spyRules: jasmine.Spy;
|
||||
|
||||
let spyEndpoint: jasmine.Spy;
|
||||
|
||||
let config: IServiceConfig = {
|
||||
replicationRuleEndpoint: '/api/policies/replication/testing'
|
||||
replicationRuleEndpoint: '/api/policies/replication/testing',
|
||||
systemInfoEndpoint: "/api/endpoints/testing"
|
||||
};
|
||||
|
||||
beforeEach(async(() => {
|
||||
@ -69,7 +90,8 @@ describe('ListReplicationRuleComponent (inline template)', () => {
|
||||
ErrorHandler,
|
||||
{ provide: SERVICE_CONFIG, useValue: config },
|
||||
{ provide: ReplicationService, useClass: ReplicationDefaultService },
|
||||
{ provide: OperationService }
|
||||
{ provide: OperationService },
|
||||
{ provide: EndpointService, useClass: EndpointDefaultService }
|
||||
]
|
||||
});
|
||||
}));
|
||||
@ -79,6 +101,11 @@ describe('ListReplicationRuleComponent (inline template)', () => {
|
||||
comp = fixture.componentInstance;
|
||||
replicationService = fixture.debugElement.injector.get(ReplicationService);
|
||||
spyRules = spyOn(replicationService, 'getReplicationRules').and.returnValues(of(mockRules));
|
||||
|
||||
endpointService = fixture.debugElement.injector.get(EndpointService);
|
||||
spyEndpoint = spyOn(endpointService, "getEndpoint").and.returnValue(
|
||||
of(mockEndpoint)
|
||||
);
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
|
@ -27,9 +27,9 @@ import {
|
||||
import { Comparator } from "../service/interface";
|
||||
import { TranslateService } from "@ngx-translate/core";
|
||||
import { map, catchError } from "rxjs/operators";
|
||||
import { Observable, forkJoin, throwError as observableThrowError } from "rxjs";
|
||||
import { Observable, forkJoin, of, throwError as observableThrowError } from "rxjs";
|
||||
import { ReplicationService } from "../service/replication.service";
|
||||
|
||||
import { EndpointService } from "../service/endpoint.service";
|
||||
import {
|
||||
ReplicationJob,
|
||||
ReplicationJobItem,
|
||||
@ -82,7 +82,9 @@ export class ListReplicationRuleComponent implements OnInit, OnChanges {
|
||||
changedRules: ReplicationRule[];
|
||||
ruleName: string;
|
||||
canDeleteRule: boolean;
|
||||
srcRegistry: string = 'docker hub';
|
||||
registryName: [] = [];
|
||||
desRegistry: [] = [];
|
||||
currentRegistry: string;
|
||||
|
||||
selectedRow: ReplicationRule;
|
||||
|
||||
@ -96,6 +98,7 @@ export class ListReplicationRuleComponent implements OnInit, OnChanges {
|
||||
enabledComparator: Comparator<ReplicationRule> = new CustomComparator<ReplicationRule>("enabled", "number");
|
||||
|
||||
constructor(private replicationService: ReplicationService,
|
||||
private endpointService: EndpointService,
|
||||
private translateService: TranslateService,
|
||||
private errorHandler: ErrorHandler,
|
||||
private operationService: OperationService,
|
||||
@ -116,6 +119,9 @@ export class ListReplicationRuleComponent implements OnInit, OnChanges {
|
||||
if (!this.projectScope) {
|
||||
this.retrieveRules();
|
||||
}
|
||||
this.translateService.get("REPLICATION.CURRENT").subscribe((res: string) => {
|
||||
this.currentRegistry = res;
|
||||
});
|
||||
}
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
let proIdChange: SimpleChange = changes["projectId"];
|
||||
@ -140,13 +146,36 @@ export class ListReplicationRuleComponent implements OnInit, OnChanges {
|
||||
// job list hidden
|
||||
this.hideJobs.emit();
|
||||
this.changedRules = this.rules;
|
||||
this.loading = false;
|
||||
// get registry name
|
||||
let targetLists: ReplicationRule[] = rules;
|
||||
if (targetLists && targetLists.length) {
|
||||
let registryList: any[] = [];
|
||||
targetLists.forEach(target => {
|
||||
let tartId: number;
|
||||
if (target.src_registry_id > 0) {
|
||||
tartId = target.src_registry_id;
|
||||
} else {
|
||||
tartId = target.dest_registry_id;
|
||||
}
|
||||
registryList.push(this.getRegistry(tartId));
|
||||
|
||||
});
|
||||
forkJoin(...registryList).subscribe((item) => {
|
||||
this.selectedRow = null;
|
||||
this.registryName = item.map(target => target.name);
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
}, error => {
|
||||
this.errorHandler.error(error);
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
getRegistry(endpointId) {
|
||||
return this.endpointService.getEndpoint(endpointId);
|
||||
}
|
||||
|
||||
replicateRule(rule: ReplicationRule): void {
|
||||
this.replicateManual.emit(rule);
|
||||
}
|
||||
|
@ -1,117 +1,135 @@
|
||||
<div class="replication-tasks">
|
||||
<section class="overview-section">
|
||||
<div class="title-wrapper clr-row">
|
||||
<div class="clr-col-lg-9">
|
||||
<div>
|
||||
<a (click)="onBack()" class="onback">< {{'PROJECT_DETAIL.REPLICATION'| translate}}</a>
|
||||
</div>
|
||||
<div class="title-block clr-row">
|
||||
<div class="clr-col-2">
|
||||
<h2 class="custom-h2">{{'REPLICATION.REPLICATION_EXECUTION'| translate}}</h2>
|
||||
<h4>{{executionId}}</h4>
|
||||
</div>
|
||||
<div class="clr-col-3">
|
||||
<span class="label label-info" *ngIf="executions === 'InProgress'">In Progress</span>
|
||||
<span class="label label-success" *ngIf="executions === 'success'">Success</span>
|
||||
<span class="label label-danger" *ngIf="executions=== 'failture'">Failture</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clr-col-3">
|
||||
<button class="btn btn-outline" (click)="stopJob()" [disabled]="stopOnGoing">{{'REPLICATION.STOPJOB' | translate}}</button>
|
||||
</div>
|
||||
<section class="overview-section">
|
||||
<div class="title-wrapper">
|
||||
<div>
|
||||
<div>
|
||||
<a (click)="onBack()" class="onback"><{{'PROJECT_DETAIL.REPLICATION'|
|
||||
translate}}</a>
|
||||
</div>
|
||||
<div class="execution-block row">
|
||||
<div class="clr-col-sm-12 clr-col-md-6">
|
||||
<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="execution-details">{{'1'}}</div>
|
||||
</section>
|
||||
<section class="detail-row">
|
||||
<span class="label label-red detail-span">{{'REPLICATION.FAILTURE'| translate}}</span>
|
||||
<div class="execution-details">{{'2'}}</div>
|
||||
</section>
|
||||
<section class="detail-row">
|
||||
<span class="label label-light-blue detail-span">{{'REPLICATION.IN_PROGRESS'| translate}}</span>
|
||||
<div class="execution-details">{{'3'}}</div>
|
||||
</section>
|
||||
</section>
|
||||
</div>
|
||||
<div class="title-block">
|
||||
<div>
|
||||
<h2 class="custom-h2 h2-style">{{'REPLICATION.REPLICATION_EXECUTION'|
|
||||
translate}}</h2>
|
||||
<span class="id-divider"></span>
|
||||
<h2 class="custom-h2 h2-style">{{executionId}}</h2>
|
||||
</div>
|
||||
<div>
|
||||
<div class="status-progress" *ngIf="executions === 'InProgress'">
|
||||
<span class="spinner spinner-inline"></span>
|
||||
<span>{{'REPLICATION.IN_PROGRESS'| translate}}</span>
|
||||
</div>
|
||||
<div class="clr-col-sm-12 clr-col-md-6">
|
||||
<div class="executions-detail">
|
||||
<div class="policy">
|
||||
<label>{{'REPLICATION.POLICY' | translate}} :</label>
|
||||
<span>{{'My 1st policy'}}</span>
|
||||
</div>
|
||||
<div class="trigger">
|
||||
<label for="">{{'REPLICATION.TRIGGER_MODE' | translate}} :</label>
|
||||
<span>{{'Schedule'}}</span>
|
||||
</div>
|
||||
<div class="start-time">
|
||||
<label for="">{{'REPLICATION.CREATION_TIME' | translate}} :</label>
|
||||
<span>{{'3/14/19, 2:26 PM'}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="status-success" *ngIf="executions === 'success'">
|
||||
<clr-icon size="18" shape="success-standard" class="color-green"></clr-icon>
|
||||
<span>{{'REPLICATION.SUCCESS'| translate}}</span>
|
||||
</div>
|
||||
<div class="status-failed" *ngIf="executions === 'failed'">
|
||||
<clr-icon size="18" shape="error-standard" class="color-red"></clr-icon>
|
||||
<span>{{'REPLICATION.FAILTURE'| translate}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<button class="btn btn-primary btn-sm" (click)="stopJob()"
|
||||
[disabled]="stopOnGoing">{{'REPLICATION.STOPJOB' | translate}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="tasks-detail">
|
||||
<h3 class="modal-title">Tasks</h3>
|
||||
<div class="row flex-items-xs-between flex-items-xs-bottom">
|
||||
<div class="action-select">
|
||||
<div class="select filterTag" [hidden]="!isOpenFilterTag">
|
||||
<select>
|
||||
<option value="username">{{"AUDIT_LOG.USERNAME" | translate | lowercase}}</option>
|
||||
<option value="repository">{{"CONFIG.REPOSITORY" | translate | lowercase}}</option>
|
||||
<option value="tag">{{"REPOSITORY.TAG" | translate | lowercase}}</option>
|
||||
<option value="operation">{{"AUDIT_LOG.OPERATION" | translate | lowercase}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<hbr-filter [withDivider]="true" (openFlag)="openFilter($event)" filterPlaceholder='{{"AUDIT_LOG.FILTER_PLACEHOLDER" | translate}}'></hbr-filter>
|
||||
<span class="refresh-btn">
|
||||
<clr-icon shape="refresh"></clr-icon>
|
||||
<span class="spinner spinner-inline" hidden></span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<clr-datagrid [(clrDgSelected)]="selectedRow">
|
||||
<clr-dg-column>{{'REPLICATION.TASK_ID'| translate}}</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'resource_type'">{{'REPLICATION.RECOURCE_TYPE' | translate}}</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'src_resource'">{{'REPLICATION.RECOURCE' | translate}}</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'dst_resource'">{{'REPLICATION.DESTINATION' | translate}}</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'status'">{{'REPLICATION.STATUS' | translate}}</clr-dg-column>
|
||||
<clr-dg-column [clrDgSortBy]="startTimeComparator">{{'REPLICATION.CREATION_TIME' | translate}}</clr-dg-column>
|
||||
<clr-dg-column [clrDgSortBy]="endTimeComparator">{{'REPLICATION.END_TIME' | translate}}</clr-dg-column>
|
||||
<clr-dg-column>{{'REPLICATION.LOGS' | translate}}</clr-dg-column>
|
||||
<clr-dg-row *clrDgItems="let t of tasks">
|
||||
<clr-dg-cell>{{t.id}}</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.dst_resource}}</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.end_time | date: 'short'}}</clr-dg-cell>
|
||||
<clr-dg-cell>
|
||||
<span *ngIf="t.status=='InProgress'; else elseBlock" class="label">{{'REPLICATION.NO_LOGS' | translate}}</span>
|
||||
<ng-template #elseBlock>
|
||||
<a target="_blank" [href]="viewLog(t.id)">
|
||||
<clr-icon shape="list"></clr-icon>
|
||||
</a>
|
||||
</ng-template>
|
||||
</clr-dg-cell>
|
||||
</clr-dg-row>
|
||||
<clr-dg-footer>
|
||||
<span *ngIf="pagination.totalItems">{{pagination.firstItem + 1}}
|
||||
-
|
||||
{{pagination.lastItem +1 }} {{'ROBOT_ACCOUNT.OF' |
|
||||
translate}} </span>
|
||||
{{pagination.totalItems }} {{'ROBOT_ACCOUNT.ITEMS' | translate}}
|
||||
<clr-dg-pagination #pagination [clrDgPageSize]="15"></clr-dg-pagination>
|
||||
</clr-dg-footer>
|
||||
</clr-datagrid>
|
||||
</div>
|
||||
<div class="execution-block">
|
||||
<div class="executions-detail">
|
||||
<div class="policy">
|
||||
<label>{{'REPLICATION.POLICY' | translate}} :</label>
|
||||
<span>{{'My 1st policy'}}</span>
|
||||
</div>
|
||||
<div class="trigger">
|
||||
<label for="">{{'REPLICATION.TRIGGER_MODE' | translate}} :</label>
|
||||
<span>{{'Schedule'}}</span>
|
||||
</div>
|
||||
<div class="start-time">
|
||||
<label for="">{{'REPLICATION.CREATION_TIME' | translate}} :</label>
|
||||
<span>{{'3/14/19, 2:26 PM'}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<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="execution-details">{{'1'}}</div>
|
||||
</section>
|
||||
<section class="detail-row">
|
||||
<span class="label label-red detail-span">{{'REPLICATION.FAILTURE'| translate}}</span>
|
||||
<div class="execution-details">{{'2'}}</div>
|
||||
</section>
|
||||
<section class="detail-row">
|
||||
<span class="label label-light-blue detail-span">{{'REPLICATION.IN_PROGRESS'| translate}}</span>
|
||||
<div class="execution-details">{{'3'}}</div>
|
||||
</section>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="tasks-detail">
|
||||
<h3 class="modal-title">Tasks</h3>
|
||||
<div class="row flex-items-xs-between flex-items-xs-bottom">
|
||||
<div class="action-select">
|
||||
<div class="select filterTag" [hidden]="!isOpenFilterTag">
|
||||
<select>
|
||||
<option value="recourceType">{{'REPLICATION.RECOURCE_TYPE' |translate}}</option>
|
||||
<option value="recource">{{'REPLICATION.RECOURCE' | translate}}</option>
|
||||
<option value="destination">{{'REPLICATION.DESTINATION' | translate}}</option>
|
||||
<option value="status">{{'REPLICATION.STATUS' | translate}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<hbr-filter [withDivider]="true" (openFlag)="openFilter($event)"
|
||||
filterPlaceholder='{{"REPLICATION.FILTER_PLACEHOLDER" | translate}}'></hbr-filter>
|
||||
<span class="refresh-btn">
|
||||
<clr-icon shape="refresh"></clr-icon>
|
||||
<span class="spinner spinner-inline" hidden></span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<clr-datagrid [(clrDgSelected)]="selectedRow" [clrDgLoading]="loading">
|
||||
<clr-dg-column>{{'REPLICATION.TASK_ID'| translate}}</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'resource_type'">{{'REPLICATION.RECOURCE_TYPE'
|
||||
| translate}}</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'src_resource'">{{'REPLICATION.RECOURCE' |
|
||||
translate}}</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'dst_resource'">{{'REPLICATION.DESTINATION' |
|
||||
translate}}</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'status'">{{'REPLICATION.STATUS' |
|
||||
translate}}</clr-dg-column>
|
||||
<clr-dg-column [clrDgSortBy]="startTimeComparator">{{'REPLICATION.CREATION_TIME'
|
||||
| translate}}</clr-dg-column>
|
||||
<clr-dg-column [clrDgSortBy]="endTimeComparator">{{'REPLICATION.END_TIME'
|
||||
| translate}}</clr-dg-column>
|
||||
<clr-dg-column>{{'REPLICATION.LOGS' | translate}}</clr-dg-column>
|
||||
<clr-dg-row *clrDgItems="let t of tasks">
|
||||
<clr-dg-cell>{{t.id}}</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.dst_resource}}</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.end_time | date: 'short'}}</clr-dg-cell>
|
||||
<clr-dg-cell>
|
||||
<span *ngIf="t.status=='InProgress'; else elseBlock" class="label">{{'REPLICATION.NO_LOGS'
|
||||
| translate}}</span>
|
||||
<ng-template #elseBlock>
|
||||
<a target="_blank" [href]="viewLog(t.id)">
|
||||
<clr-icon shape="list"></clr-icon>
|
||||
</a>
|
||||
</ng-template>
|
||||
</clr-dg-cell>
|
||||
</clr-dg-row>
|
||||
<clr-dg-footer>
|
||||
<span *ngIf="pagination.totalItems">{{pagination.firstItem + 1}}
|
||||
-
|
||||
{{pagination.lastItem +1 }} {{'ROBOT_ACCOUNT.OF' |
|
||||
translate}} </span>
|
||||
{{pagination.totalItems }} {{'ROBOT_ACCOUNT.ITEMS' | translate}}
|
||||
<clr-dg-pagination #pagination [clrDgPageSize]="15"></clr-dg-pagination>
|
||||
</clr-dg-footer>
|
||||
</clr-datagrid>
|
||||
</div>
|
||||
</div>
|
@ -3,11 +3,33 @@
|
||||
.title-wrapper {
|
||||
.onback{
|
||||
color: #007cbb;
|
||||
font-size: 12px;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
}
|
||||
h4 {
|
||||
margin-top: 8px;
|
||||
.title-block {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
>div:first-child {
|
||||
width: 210px;
|
||||
}
|
||||
>div:nth-child(2) {
|
||||
width: 140px;
|
||||
span {
|
||||
color: #007cbb;
|
||||
font-size: 12px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
.id-divider {
|
||||
display: inline-block;
|
||||
height: 25px;
|
||||
width: 2px;
|
||||
background-color: #cccccc;
|
||||
margin: 0 20px;
|
||||
}
|
||||
.h2-style {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
.execution-block {
|
||||
@ -21,7 +43,6 @@
|
||||
display: flex;
|
||||
.detail-span {
|
||||
flex:0 0 100px;
|
||||
font-weight: 600;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.execution-details {
|
||||
@ -31,9 +52,14 @@
|
||||
}
|
||||
}
|
||||
.executions-detail {
|
||||
font-weight: 600;
|
||||
span {
|
||||
margin-left: 5px;
|
||||
width: 400px;
|
||||
label {
|
||||
display: inline-block;
|
||||
color: black;
|
||||
width: 120px;
|
||||
}
|
||||
>div {
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -60,4 +86,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { Component, OnInit, Input } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { ReplicationService } from "../../service/replication.service";
|
||||
import { map, catchError } from "rxjs/operators";
|
||||
import { Observable, forkJoin, throwError as observableThrowError } from "rxjs";
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { finalize } from "rxjs/operators";
|
||||
import { ErrorHandler } from "../../error-handler/error-handler";
|
||||
import { ReplicationJob, ReplicationTasks, Comparator, ReplicationJobItem } from "../../service/interface";
|
||||
import { CustomComparator } from "../../utils";
|
||||
@ -14,7 +14,11 @@ import { CustomComparator } from "../../utils";
|
||||
export class ReplicationTasksComponent implements OnInit {
|
||||
isOpenFilterTag: boolean;
|
||||
selectedRow: [];
|
||||
loading = false;
|
||||
searchTask: string;
|
||||
defaultFilter = "recourceType";
|
||||
tasks: ReplicationTasks[] = [];
|
||||
tasksCopy: ReplicationTasks[] = [];
|
||||
stopOnGoing: boolean;
|
||||
executions: string = 'InProgress';
|
||||
@Input() executionId: string;
|
||||
@ -26,15 +30,16 @@ export class ReplicationTasksComponent implements OnInit {
|
||||
>("end_time", "date");
|
||||
|
||||
constructor(
|
||||
private translate: TranslateService,
|
||||
private router: Router,
|
||||
private replicationService: ReplicationService,
|
||||
private errorHandler: ErrorHandler,
|
||||
) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
// this.getExecutions();
|
||||
this.getTasks();
|
||||
this.clrLoadTasks();
|
||||
// this.executions.status = 'success';
|
||||
this.searchTask = '';
|
||||
}
|
||||
|
||||
// getExecutions(): void {
|
||||
@ -54,9 +59,12 @@ export class ReplicationTasksComponent implements OnInit {
|
||||
stopJob() {
|
||||
this.stopOnGoing = true;
|
||||
this.replicationService.stopJobs(this.executionId)
|
||||
.subscribe(res => {
|
||||
.subscribe(response => {
|
||||
this.stopOnGoing = false;
|
||||
// this.getExecutions();
|
||||
this.translate.get("REPLICATION.STOP_SUCCESS", { param: this.executionId }).subscribe((res: string) => {
|
||||
this.errorHandler.info(res);
|
||||
});
|
||||
},
|
||||
error => {
|
||||
this.errorHandler.error(error);
|
||||
@ -64,13 +72,33 @@ export class ReplicationTasksComponent implements OnInit {
|
||||
}
|
||||
|
||||
viewLog(taskId: number | string): string {
|
||||
return this.replicationService.getJobBaseUrl() + "/" + this.executionId + "/tasks/" + taskId + "/log";
|
||||
return this.replicationService.getJobBaseUrl() + "/executions/" + this.executionId + "/tasks/" + taskId + "/log";
|
||||
}
|
||||
|
||||
getTasks(): void {
|
||||
clrLoadTasks(): void {
|
||||
this.loading = true;
|
||||
this.replicationService.getReplicationTasks(this.executionId)
|
||||
.pipe(finalize(() => (this.loading = false)))
|
||||
.subscribe(tasks => {
|
||||
this.tasks = tasks.map(x => Object.assign({}, x));
|
||||
if (this.defaultFilter === 'recourceType') {
|
||||
this.tasks = tasks.filter(x =>
|
||||
x.resource_type.includes(this.searchTask)
|
||||
);
|
||||
} else if (this.defaultFilter === 'recource') {
|
||||
this.tasks = tasks.filter(x =>
|
||||
x.src_resource.includes(this.searchTask)
|
||||
);
|
||||
} else if (this.defaultFilter === 'destination') {
|
||||
this.tasks = tasks.filter(x =>
|
||||
x.dst_resource.includes(this.searchTask)
|
||||
);
|
||||
} else {
|
||||
this.tasks = tasks.filter(x =>
|
||||
x.status.includes(this.searchTask)
|
||||
);
|
||||
}
|
||||
|
||||
this.tasksCopy = tasks.map(x => Object.assign({}, x));
|
||||
},
|
||||
error => {
|
||||
this.errorHandler.error(error);
|
||||
@ -80,12 +108,31 @@ export class ReplicationTasksComponent implements OnInit {
|
||||
this.router.navigate(["harbor", "replications"]);
|
||||
}
|
||||
|
||||
selectFilter($event: any): void {
|
||||
this.defaultFilter = $event['target'].value;
|
||||
this.doSearch(this.searchTask);
|
||||
}
|
||||
|
||||
// refresh icon
|
||||
refreshTasks(): void {
|
||||
this.searchTask = '';
|
||||
this.clrLoadTasks();
|
||||
}
|
||||
|
||||
doSearch(value: string): void {
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
this.searchTask = value.trim();
|
||||
this.clrLoadTasks();
|
||||
}
|
||||
|
||||
openFilter(isOpen: boolean): void {
|
||||
if (isOpen) {
|
||||
this.isOpenFilterTag = true;
|
||||
} else {
|
||||
this.isOpenFilterTag = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -26,7 +26,7 @@
|
||||
<h5 class="flex-items-xs-bottom option-left-down">{{'REPLICATION.REPLICATION_EXECUTIONS' | translate}}</h5>
|
||||
<div class="flex-items-xs-bottom option-right-down">
|
||||
<button class="btn btn-link" (click)="toggleSearchJobOptionalName(currentJobSearchOption)">{{toggleJobSearchOption[currentJobSearchOption] | translate}}</button>
|
||||
<hbr-filter [withDivider]="true" filterPlaceholder='{{"REPLICATION.FILTER_JOBS_PLACEHOLDER" | translate}}' (filterEvt)="doSearchJobs($event)"
|
||||
<hbr-filter [withDivider]="true" filterPlaceholder='{{"REPLICATION.FILTER_EXECUTIONS_PLACEHOLDER" | translate}}' (filterEvt)="doSearchJobs($event)"
|
||||
[currentValue]="search.repoName"></hbr-filter>
|
||||
<span class="refresh-btn" (click)="refreshJobs()">
|
||||
<clr-icon shape="refresh"></clr-icon>
|
||||
|
@ -28,7 +28,7 @@
|
||||
}
|
||||
|
||||
.row-right {
|
||||
padding-right: 50px;
|
||||
margin-left: 564px;
|
||||
}
|
||||
|
||||
.replication-row {
|
||||
|
@ -27,6 +27,20 @@ import { of } from 'rxjs';
|
||||
|
||||
|
||||
describe('Replication Component (inline template)', () => {
|
||||
let mockEndpoint: Endpoint = {
|
||||
id: 1,
|
||||
credential: {
|
||||
access_key: "admin",
|
||||
access_secret: "",
|
||||
type: "basic"
|
||||
},
|
||||
description: "test",
|
||||
insecure: false,
|
||||
name: "target_01",
|
||||
type: "Harbor",
|
||||
url: "https://10.117.4.151"
|
||||
};
|
||||
|
||||
|
||||
let mockRules: ReplicationRule[] = [
|
||||
{
|
||||
@ -128,6 +142,7 @@ describe('Replication Component (inline template)', () => {
|
||||
let spyRules: jasmine.Spy;
|
||||
let spyJobs: jasmine.Spy;
|
||||
let spyEndpoint: jasmine.Spy;
|
||||
let spyEndpoints: jasmine.Spy;
|
||||
|
||||
let deGrids: DebugElement[];
|
||||
let deRules: DebugElement;
|
||||
@ -138,7 +153,7 @@ describe('Replication Component (inline template)', () => {
|
||||
|
||||
let config: IServiceConfig = {
|
||||
replicationRuleEndpoint: '/api/policies/replication/testing',
|
||||
replicationBaseEndpoint: '/api/replication/testing'
|
||||
systemInfoEndpoint: "/api/endpoints/testing"
|
||||
};
|
||||
|
||||
beforeEach(async(() => {
|
||||
@ -187,8 +202,8 @@ describe('Replication Component (inline template)', () => {
|
||||
spyJobs = spyOn(replicationService, 'getExecutions').and.returnValues(of(mockJob));
|
||||
|
||||
|
||||
spyEndpoint = spyOn(endpointService, 'getEndpoints').and.returnValues(of(mockEndpoints));
|
||||
|
||||
spyEndpoints = spyOn(endpointService, 'getEndpoints').and.returnValues(of(mockEndpoints));
|
||||
spyEndpoint = spyOn(endpointService, "getEndpoint").and.returnValue(of(mockEndpoint));
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
|
@ -278,7 +278,7 @@ export class ReplicationDefaultService extends ReplicationService {
|
||||
if (!executionId) {
|
||||
return observableThrowError("Bad argument");
|
||||
}
|
||||
let url: string = `${this._replicateUrl}/${executionId}/tasks`;
|
||||
let url: string = `${this._replicateUrl}/executions/${executionId}/tasks`;
|
||||
return this.http
|
||||
.get(url, HTTP_GET_OPTIONS)
|
||||
.pipe(map(response => response.json() as ReplicationTasks)
|
||||
@ -385,10 +385,10 @@ export class ReplicationDefaultService extends ReplicationService {
|
||||
if (!queryParams) {
|
||||
queryParams = new RequestQueryParams();
|
||||
}
|
||||
|
||||
let url: string = `${this._replicateUrl}/executions`;
|
||||
queryParams.set("policy_id", "" + ruleId);
|
||||
return this.http
|
||||
.get(this._replicateUrl, buildHttpRequestOptions(queryParams))
|
||||
.get(url, buildHttpRequestOptions(queryParams))
|
||||
.pipe(map(response => {
|
||||
let result: ReplicationJob = {
|
||||
metadata: {
|
||||
@ -435,7 +435,7 @@ export class ReplicationDefaultService extends ReplicationService {
|
||||
if (!jobId || jobId <= 0) {
|
||||
return observableThrowError("Bad request argument.");
|
||||
}
|
||||
let requestUrl: string = `${this._replicateUrl}/${jobId}`;
|
||||
let requestUrl: string = `${this._replicateUrl}/executions/${jobId}`;
|
||||
|
||||
return this.http
|
||||
.put(
|
||||
|
@ -331,7 +331,10 @@
|
||||
"OF": "of"
|
||||
},
|
||||
"REPLICATION": {
|
||||
"CURRENT": "current",
|
||||
"FILTER_PLACEHOLDER": "Filter Tasks",
|
||||
"STOP_TITLE": "Confirm Stop Executions",
|
||||
"STOP_SUCCESS": "Stop Execution {{param}} Successful",
|
||||
"STOP_SUMMARY": "Do you want to stop the executions {{param}}?",
|
||||
"TASK_ID":"Task ID",
|
||||
"RECOURCE_TYPE": "Recource Type",
|
||||
@ -340,14 +343,14 @@
|
||||
"POLICY": "Policy",
|
||||
"DURATION": "Duration",
|
||||
"SUCCESS_RATE": "Success Rate",
|
||||
"SUCCESS": "Success",
|
||||
"FAILTURE": "Failture",
|
||||
"IN_PROGRESS": "In Progress",
|
||||
"SUCCESS": "SUCCESS",
|
||||
"FAILTURE": "FAILTURE",
|
||||
"IN_PROGRESS": "IN PROGRESS",
|
||||
"REPLICATION_RULE": "Replication Rule",
|
||||
"NEW_REPLICATION_RULE": "New Replication Rule",
|
||||
"ENDPOINTS": "Endpoints",
|
||||
"FILTER_POLICIES_PLACEHOLDER": "Filter Rules",
|
||||
"FILTER_JOBS_PLACEHOLDER": "Filter Jobs",
|
||||
"FILTER_EXECUTIONS_PLACEHOLDER": "Filter Executions",
|
||||
"DELETION_TITLE": "Confirm Rules Deletion",
|
||||
"DELETION_SUMMARY": "Do you want to delete rules {{param}}?",
|
||||
"REPLICATION_TITLE": "Confirm Rules replication",
|
||||
|
@ -330,7 +330,10 @@
|
||||
"OF": "of"
|
||||
},
|
||||
"REPLICATION": {
|
||||
"CURRENT": "current",
|
||||
"FILTER_PLACEHOLDER": "Filter Tasks",
|
||||
"STOP_TITLE": "Confirme Stop Executions",
|
||||
"STOP_SUCCESS": "Stop Execution {{param}} Successful",
|
||||
"STOP_SUMMARY": "De que desea detener las ejecuciones {{param}}?",
|
||||
"TASK_ID":"Task ID",
|
||||
"RECOURCE_TYPE": "Recource Type",
|
||||
@ -339,16 +342,16 @@
|
||||
"POLICY": "Policy",
|
||||
"DURATION": "Duration",
|
||||
"SUCCESS_RATE": "Success Rate",
|
||||
"SUCCESS": "Success",
|
||||
"FAILTURE": "Failture",
|
||||
"IN_PROGRESS": "In Progress",
|
||||
"SUCCESS": "SUCCESS",
|
||||
"FAILTURE": "FAILTURE",
|
||||
"IN_PROGRESS": "IN PROGRESS",
|
||||
"STOP_EXECUTIONS": "Stop Execution",
|
||||
"ID":"ID",
|
||||
"REPLICATION_RULE": "Reglas de Replicación",
|
||||
"NEW_REPLICATION_RULE": "Nueva Regla de Replicación",
|
||||
"ENDPOINTS": "Endpoints",
|
||||
"FILTER_POLICIES_PLACEHOLDER": "Filtrar Reglas",
|
||||
"FILTER_JOBS_PLACEHOLDER": "Filtrar Trabajos",
|
||||
"FILTER_EXECUTIONS_PLACEHOLDER": "Filter Ejecuciones",
|
||||
"DELETION_TITLE": "Confirmar Eliminación de Regla",
|
||||
"DELETION_SUMMARY": "¿Quiere eliminar la regla {{param}}?",
|
||||
"DELETION_TITLE_FAILURE": "failed to delete Rule Deletion",
|
||||
|
@ -315,7 +315,10 @@
|
||||
"OF": "de"
|
||||
},
|
||||
"REPLICATION": {
|
||||
"CURRENT": "current",
|
||||
"FILTER_PLACEHOLDER": "Filter Tasks",
|
||||
"STOP_TITLE": "Confirmer arrêter les exécutions",
|
||||
"STOP_SUCCESS": "Stop Execution {{param}} Successful",
|
||||
"STOP_SUMMARY": "Voulez-vous arrêter les exécutions {{param}}?",
|
||||
"TASK_ID":"Task ID",
|
||||
"RECOURCE_TYPE": "Recource Type",
|
||||
@ -324,16 +327,16 @@
|
||||
"POLICY": "Policy",
|
||||
"DURATION": "Duration",
|
||||
"SUCCESS_RATE": "Success Rate",
|
||||
"SUCCESS": "Success",
|
||||
"FAILTURE": "Failture",
|
||||
"IN_PROGRESS": "In Progress",
|
||||
"SUCCESS": "SUCCESS",
|
||||
"FAILTURE": "FAILTURE",
|
||||
"IN_PROGRESS": "IN PROGRESS",
|
||||
"STOP_EXECUTIONS": "Stop Execution",
|
||||
"ID":"ID",
|
||||
"REPLICATION_RULE": "Règle de Réplication",
|
||||
"NEW_REPLICATION_RULE": "Nouvelle Règle de Réplication",
|
||||
"ENDPOINTS": "Points finaux",
|
||||
"FILTER_POLICIES_PLACEHOLDER": "Filtrer les Règles",
|
||||
"FILTER_JOBS_PLACEHOLDER": "Filtrer les Travaux",
|
||||
"FILTER_EXECUTIONS_PLACEHOLDER": "Filter Exécutions",
|
||||
"DELETION_TITLE": "Confirmer la suppression de la Règle",
|
||||
"DELETION_SUMMARY": "Voulez-vous supprimer la règle {{param}} ?",
|
||||
"DELETION_TITLE_FAILURE": "n'a pas supprimé la règle",
|
||||
|
@ -329,7 +329,10 @@
|
||||
"OF": "de"
|
||||
},
|
||||
"REPLICATION": {
|
||||
"CURRENT": "current",
|
||||
"FILTER_PLACEHOLDER": "Filter Tasks",
|
||||
"STOP_TITLE": "Confirme as execuções de parada",
|
||||
"STOP_SUCCESS": "Stop Execution {{param}} Successful",
|
||||
"STOP_SUMMARY": "Você quer parar as execuções? {{param}}?",
|
||||
"TASK_ID":"Task ID",
|
||||
"RECOURCE_TYPE": "Recource Type",
|
||||
@ -338,16 +341,16 @@
|
||||
"POLICY": "Policy",
|
||||
"DURATION": "Duration",
|
||||
"SUCCESS_RATE": "Success Rate",
|
||||
"SUCCESS": "Success",
|
||||
"FAILTURE": "Failture",
|
||||
"IN_PROGRESS": "In Progress",
|
||||
"SUCCESS": "SUCCESS",
|
||||
"FAILTURE": "FAILTURE",
|
||||
"IN_PROGRESS": "IN PROGRESS",
|
||||
"STOP_EXECUTIONS": "Stop Execution",
|
||||
"ID":"ID",
|
||||
"REPLICATION_RULE": "Regra de replicação",
|
||||
"NEW_REPLICATION_RULE": "Nova regra de replicação",
|
||||
"ENDPOINTS": "Endpoints",
|
||||
"FILTER_POLICIES_PLACEHOLDER": "Filtrar regras",
|
||||
"FILTER_JOBS_PLACEHOLDER": "Filtrar tarefas",
|
||||
"FILTER_EXECUTIONS_PLACEHOLDER": "Execuções de Filtro",
|
||||
"DELETION_TITLE": "Confirmar remoção de regras",
|
||||
"DELETION_SUMMARY": "Você quer remover a regra {{param}}?",
|
||||
"REPLICATION_TITLE": "Confirmar regras de replicação",
|
||||
|
@ -330,7 +330,10 @@
|
||||
"OF": "共计"
|
||||
},
|
||||
"REPLICATION": {
|
||||
"CURRENT": "当前仓库",
|
||||
"FILTER_PLACEHOLDER": "过滤任务",
|
||||
"STOP_TITLE": "确认停止任务",
|
||||
"STOP_SUCCESS": "停止任务 {{param}} 成功",
|
||||
"STOP_SUMMARY": "确认停止任务{{param}}?",
|
||||
"TASK_ID":"任务ID",
|
||||
"RECOURCE_TYPE": "源类型",
|
||||
@ -348,7 +351,7 @@
|
||||
"NEW_REPLICATION_RULE": "新建规则",
|
||||
"ENDPOINTS": "目标",
|
||||
"FILTER_POLICIES_PLACEHOLDER": "过滤规则",
|
||||
"FILTER_JOBS_PLACEHOLDER": "过滤任务",
|
||||
"FILTER_EXECUTIONS_PLACEHOLDER": "过滤任务",
|
||||
"DELETION_TITLE": "删除规则确认",
|
||||
"DELETION_SUMMARY": "确认删除规则 {{param}}?",
|
||||
"DELETION_TITLE_FAILURE": "规则确认删除失败",
|
||||
|
Loading…
Reference in New Issue
Block a user