-
{{'REPLICATION.REPLICATION_JOBS' | translate}}
+
{{'REPLICATION.REPLICATION_EXECUTIONS' | translate}}
-
+
-
+
- {{'REPLICATION.NAME' | translate}}
- {{'REPLICATION.STATUS' | translate}}
- {{'REPLICATION.OPERATION' | translate}}
+ {{'REPLICATION.ID' | translate}}
+ {{'REPLICATION.REPLICATION_TRIGGER' | translate}}
{{'REPLICATION.CREATION_TIME' | translate}}
- {{'REPLICATION.UPDATE_TIME' | translate}}
- {{'REPLICATION.LOGS' | translate}}
+ {{'REPLICATION.DURATION' | translate}}
+ {{'REPLICATION.SUCCESS_RATE' | translate}}
+ {{'REPLICATION.STATUS' | translate}}
{{'REPLICATION.JOB_PLACEHOLDER' | translate }}
-
- {{j.repository}}
- {{j.status}}
- {{j.operation}}
- {{j.creation_time | date: 'short'}}
- {{j.update_time | date: 'short'}}
+
- {{'REPLICATION.NO_LOGS' | translate}}
-
-
-
-
-
+ {{j.id}}
+ {{j.trigger}}
+ {{j.start_time | date: 'short'}}
+ {{'3mins'}}
+
+ {{'90%'}}
+
+ {{j.status}}
{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'REPLICATION.OF' | translate}}
@@ -86,4 +83,5 @@
+
\ No newline at end of file
diff --git a/src/portal/lib/src/replication/replication.component.spec.ts b/src/portal/lib/src/replication/replication.component.spec.ts
index 018ac4452..25a32bbfd 100644
--- a/src/portal/lib/src/replication/replication.component.spec.ts
+++ b/src/portal/lib/src/replication/replication.component.spec.ts
@@ -22,6 +22,7 @@ import {ProjectDefaultService, ProjectService} from "../service/project.service"
import {OperationService} from "../operation/operation.service";
import {FilterLabelComponent} from "../create-edit-rule/filter-label.component";
import {LabelPieceComponent} from "../label-piece/label-piece.component";
+import { RouterTestingModule } from '@angular/router/testing';
describe('Replication Component (inline template)', () => {
@@ -208,14 +209,15 @@ describe('Replication Component (inline template)', () => {
let config: IServiceConfig = {
replicationRuleEndpoint: '/api/policies/replication/testing',
- replicationJobEndpoint: '/api/jobs/replication/testing'
+ replicationBaseEndpoint: '/api/replication/executions/testing'
};
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
SharedModule,
- NoopAnimationsModule
+ NoopAnimationsModule,
+ RouterTestingModule
],
declarations: [
ReplicationComponent,
@@ -253,7 +255,7 @@ describe('Replication Component (inline template)', () => {
endpointService = fixtureCreate.debugElement.injector.get(EndpointService);
spyRules = spyOn(replicationService, 'getReplicationRules').and.returnValues(Promise.resolve(mockRules));
- spyJobs = spyOn(replicationService, 'getJobs').and.returnValues(Promise.resolve(mockJob));
+ spyJobs = spyOn(replicationService, 'getExecutions').and.returnValues(Promise.resolve(mockJob));
spyEndpoint = spyOn(endpointService, 'getEndpoints').and.returnValues(Promise.resolve(mockEndpoints));
diff --git a/src/portal/lib/src/replication/replication.component.ts b/src/portal/lib/src/replication/replication.component.ts
index ece3c95da..75da85ac1 100644
--- a/src/portal/lib/src/replication/replication.component.ts
+++ b/src/portal/lib/src/replication/replication.component.ts
@@ -21,8 +21,8 @@ import {
EventEmitter
} from "@angular/core";
import { Comparator, State } from "../service/interface";
-import { Subscription, forkJoin, timer} from "rxjs";
-
+import { Subscription, forkJoin, timer, throwError} from "rxjs";
+import { finalize, catchError, map } from "rxjs/operators";
import { TranslateService } from "@ngx-translate/core";
@@ -58,6 +58,8 @@ import { ConfirmationAcknowledgement } from "../confirmation-dialog/confirmation
import {operateChanges, OperationState, OperateInfo} from "../operation/operate";
import {OperationService} from "../operation/operation.service";
+import { Router } from "@angular/router";
+
const ruleStatus: { [key: string]: any } = [
{ key: "all", description: "REPLICATION.ALL_STATUS" },
{ key: "1", description: "REPLICATION.ENABLED" },
@@ -124,6 +126,7 @@ export class ReplicationComponent implements OnInit, OnDestroy {
changedRules: ReplicationRule[];
+ selectedRow: ReplicationJobItem[] = [];
rules: ReplicationRule[];
loading: boolean;
isStopOnGoing: boolean;
@@ -144,12 +147,15 @@ export class ReplicationComponent implements OnInit, OnDestroy {
@ViewChild("replicationConfirmDialog")
replicationConfirmDialog: ConfirmationDialogComponent;
+ @ViewChild("StopConfirmDialog")
+ StopConfirmDialog: ConfirmationDialogComponent;
+
creationTimeComparator: Comparator
= new CustomComparator<
ReplicationJob
- >("creation_time", "date");
+ >("start_time", "date");
updateTimeComparator: Comparator = new CustomComparator<
ReplicationJob
- >("update_time", "date");
+ >("end_time", "date");
// Server driven pagination
currentPage: number = 1;
@@ -160,6 +166,7 @@ export class ReplicationComponent implements OnInit, OnDestroy {
timerDelay: Subscription;
constructor(
+ private router: Router,
private errorHandler: ErrorHandler,
private replicationService: ReplicationService,
private operationService: OperationService,
@@ -197,6 +204,11 @@ export class ReplicationComponent implements OnInit, OnDestroy {
this.goToRegistry.emit();
}
+ goToLink(exeId: number): void {
+ let linkUrl = ["harbor", "replications", exeId, "tasks"];
+ this.router.navigate(linkUrl);
+ }
+
// Server driven data loading
clrLoadJobs(state: State): void {
if (!state || !state.page || !this.search.ruleId) {
@@ -237,7 +249,7 @@ export class ReplicationComponent implements OnInit, OnDestroy {
this.jobsLoading = false;
toPromise(
- this.replicationService.getJobs(this.search.ruleId, params)
+ this.replicationService.getExecutions(this.search.ruleId, params)
)
.then(response => {
this.totalCount = response.metadata.xTotalCount;
@@ -394,18 +406,68 @@ export class ReplicationComponent implements OnInit, OnDestroy {
this.hiddenJobList = true;
}
- stopJobs() {
- if (this.jobs && this.jobs.length) {
- this.isStopOnGoing = true;
- toPromise(this.replicationService.stopJobs(this.jobs[0].policy_id))
- .then(res => {
- this.refreshJobs();
- this.isStopOnGoing = false;
- })
- .catch(error => this.errorHandler.error(error));
+ openStopExecutionsDialog(targets: ReplicationJobItem[]) {
+ let ExecutionId = targets.map(robot => robot.id).join(",");
+ let StopExecutionsMessage = new ConfirmationMessage(
+ "REPLICATION.STOP_TITLE",
+ "REPLICATION.STOP_SUMMARY",
+ ExecutionId,
+ targets,
+ ConfirmationTargets.STOP_EXECUTIONS,
+ ConfirmationButtons.STOP_CANCEL
+ );
+ this.StopConfirmDialog.open(StopExecutionsMessage);
+ }
+
+ confirmStop(message: ConfirmationAcknowledgement) {
+ if (
+ message &&
+ message.state === ConfirmationState.CONFIRMED &&
+ message.source === ConfirmationTargets.STOP_EXECUTIONS
+ ) {
+ this.StopExecutions(message.data);
}
}
+ StopExecutions(targets: ReplicationJobItem[]): void {
+ if (targets && targets.length < 1) {
+ return;
+ }
+
+ this.isStopOnGoing = true;
+ if (this.jobs && this.jobs.length) {
+ let ExecutionsStop$ = targets.map(target => this.StopOperate(target));
+ forkJoin(ExecutionsStop$)
+ .pipe(
+ catchError(err => throwError(err)),
+ finalize(() => {
+ this.refreshJobs();
+ this.isStopOnGoing = false;
+ this.selectedRow = [];
+ })
+ )
+ .subscribe(() => { });
+ }
+ }
+
+ StopOperate(targets: ReplicationJobItem): any {
+ let operMessage = new OperateInfo();
+ operMessage.name = "OPERATION.STOP_EXECUTIONS";
+ operMessage.data.id = targets.id;
+ operMessage.state = OperationState.progressing;
+ operMessage.data.name = targets.id;
+ this.operationService.publishInfo(operMessage);
+
+ return this.replicationService
+ .stopJobs(targets.id)
+ .pipe(
+ map(
+ () => operateChanges(operMessage, OperationState.success),
+ err => operateChanges(operMessage, OperationState.failure, err)
+ )
+ );
+ }
+
reloadRules(isReady: boolean) {
if (isReady) {
this.search.ruleName = "";
@@ -453,8 +515,4 @@ export class ReplicationComponent implements OnInit, OnDestroy {
this.search.endTimestamp = toTimestamp;
this.loadFirstPage();
}
-
- viewLog(jobId: number | string): string {
- return this.replicationService.getJobBaseUrl() + "/" + jobId + "/log";
- }
}
diff --git a/src/portal/lib/src/service.config.ts b/src/portal/lib/src/service.config.ts
index 185d80d00..c82fd8ae4 100644
--- a/src/portal/lib/src/service.config.ts
+++ b/src/portal/lib/src/service.config.ts
@@ -66,16 +66,6 @@ export interface IServiceConfig {
*/
replicationRuleEndpoint?: string;
-
- /**
- * The base endpoint of the service used to handle the replication jobs.
- *
- *
- * * {string}
- * @memberOf IServiceConfig
- */
- replicationJobEndpoint?: string;
-
/**
* The base endpoint of the service used to handle vulnerability scanning.
*
diff --git a/src/portal/lib/src/service/endpoint.service.ts b/src/portal/lib/src/service/endpoint.service.ts
index f1ebc148f..7a9cabb02 100644
--- a/src/portal/lib/src/service/endpoint.service.ts
+++ b/src/portal/lib/src/service/endpoint.service.ts
@@ -132,7 +132,7 @@ export class EndpointDefaultService extends EndpointService {
super();
this._endpointUrl = config.targetBaseEndpoint
? config.targetBaseEndpoint
- : "/api/targets";
+ : "/api/registries";
}
public getEndpoints(
diff --git a/src/portal/lib/src/service/interface.ts b/src/portal/lib/src/service/interface.ts
index 91c34601a..eb1fc802c 100644
--- a/src/portal/lib/src/service/interface.ts
+++ b/src/portal/lib/src/service/interface.ts
@@ -103,14 +103,24 @@ export interface ReplicationRule extends Base {
filters: Filter[];
replicate_existing_image_now?: boolean;
replicate_deletion?: boolean;
+ // id?: number;
+ // name: string;
+ // description: string;
+ // src_registry_id: number;
+ // src_namespaces: [];
+ // dest_registry_id: number;
+ // dest_namespace: string;
+ // trigger: Trigger;
+ // filter: Filter[];
+ // deletion: boolean;
+ // override: boolean;
+ // enabled: boolean;
}
export class Filter {
- kind: string;
- pattern: string;
- constructor(kind: string, pattern: string) {
- this.kind = kind;
- this.pattern = pattern;
+ type: string;
+ constructor(type: string) {
+ this.type = type;
}
}
@@ -146,6 +156,7 @@ export interface ReplicationJob {
*/
export interface ReplicationJobItem extends Base {
[key: string]: any | any[];
+ id: number;
status: string;
repository: string;
policy_id: number;
@@ -153,6 +164,22 @@ export interface ReplicationJobItem extends Base {
tags: string;
}
+/**
+ * Interface for replication tasks item.
+ *
+ **
+ * interface ReplicationTasks
+ */
+export interface ReplicationTasks extends Base {
+ [key: string]: any | any[];
+ id: number;
+ execution_id: number;
+ resource_type: string;
+ src_resource: string;
+ dst_resource: string;
+ job_id: number;
+ status: string;
+}
/**
* Interface for storing metadata of response.
*
diff --git a/src/portal/lib/src/service/job-log.service.spec.ts b/src/portal/lib/src/service/job-log.service.spec.ts
index 9ee59dbf5..7440d0276 100644
--- a/src/portal/lib/src/service/job-log.service.spec.ts
+++ b/src/portal/lib/src/service/job-log.service.spec.ts
@@ -6,7 +6,7 @@ import { SERVICE_CONFIG, IServiceConfig } from '../service.config';
describe('JobLogService', () => {
const mockConfig: IServiceConfig = {
- replicationJobEndpoint: "/api/jobs/replication/testing",
+ replicationBaseEndpoint: "/api/replication/executions/testing",
scanJobEndpoint: "/api/jobs/scan/testing"
};
@@ -33,7 +33,7 @@ describe('JobLogService', () => {
it('should be initialized', inject([JobLogDefaultService], (service: JobLogService) => {
expect(service).toBeTruthy();
- expect(config.replicationJobEndpoint).toEqual("/api/jobs/replication/testing");
+ expect(config.replicationBaseEndpoint).toEqual("/api/replication/executions/testing");
expect(config.scanJobEndpoint).toEqual("/api/jobs/scan/testing");
}));
});
diff --git a/src/portal/lib/src/service/job-log.service.ts b/src/portal/lib/src/service/job-log.service.ts
index f44d780ca..90363916b 100644
--- a/src/portal/lib/src/service/job-log.service.ts
+++ b/src/portal/lib/src/service/job-log.service.ts
@@ -47,9 +47,9 @@ export class JobLogDefaultService extends JobLogService {
@Inject(SERVICE_CONFIG) config: IServiceConfig
) {
super();
- this._replicationJobBaseUrl = config.replicationJobEndpoint
- ? config.replicationJobEndpoint
- : "/api/jobs/replication";
+ this._replicationJobBaseUrl = config.replicationBaseEndpoint
+ ? config.replicationBaseEndpoint
+ : "/api/replication/executions";
this._scanningJobBaseUrl = config.scanJobEndpoint
? config.scanJobEndpoint
: "/api/jobs/scan";
diff --git a/src/portal/lib/src/service/replication.service.spec.ts b/src/portal/lib/src/service/replication.service.spec.ts
index b5022e1cb..6c3fae9cc 100644
--- a/src/portal/lib/src/service/replication.service.spec.ts
+++ b/src/portal/lib/src/service/replication.service.spec.ts
@@ -7,7 +7,7 @@ import { SERVICE_CONFIG, IServiceConfig } from '../service.config';
describe('ReplicationService', () => {
const mockConfig: IServiceConfig = {
replicationRuleEndpoint: "/api/policies/replication/testing",
- replicationJobEndpoint: "/api/jobs/replication/testing"
+ replicationBaseEndpoint: "/api/replication/executions/testing"
};
let config: IServiceConfig;
@@ -38,6 +38,6 @@ describe('ReplicationService', () => {
it('should inject the right config', () => {
expect(config).toBeTruthy();
expect(config.replicationRuleEndpoint).toEqual("/api/policies/replication/testing");
- expect(config.replicationJobEndpoint).toEqual("/api/jobs/replication/testing");
+ expect(config.replicationBaseEndpoint).toEqual("/api/replication/executions/testing");
});
});
diff --git a/src/portal/lib/src/service/replication.service.ts b/src/portal/lib/src/service/replication.service.ts
index 6f72a7f63..9303d9354 100644
--- a/src/portal/lib/src/service/replication.service.ts
+++ b/src/portal/lib/src/service/replication.service.ts
@@ -1,6 +1,5 @@
import { Http } from "@angular/http";
import { Injectable, Inject } from "@angular/core";
-import { Observable } from "rxjs";
import { SERVICE_CONFIG, IServiceConfig } from "../service.config";
import {
@@ -11,10 +10,12 @@ import {
import {
ReplicationJob,
ReplicationRule,
- ReplicationJobItem
+ ReplicationJobItem,
+ ReplicationTasks
} from "./interface";
import { RequestQueryParams } from "./RequestQueryParams";
-
+import { map, catchError } from "rxjs/operators";
+import { Observable, throwError as observableThrowError } from "rxjs";
/**
* Define the service methods to handle the replication (rule and job) related things.
*
@@ -59,6 +60,18 @@ export abstract class ReplicationService {
ruleId: number | string
): Observable | Promise | ReplicationRule;
+
+ /**
+ * Get the specified replication task.
+ *
+ * @abstract
+ * returns {(Observable)}
+ *
+ * @memberOf ReplicationService
+ */
+ abstract getReplicationTasks(
+ executionId: number | string
+ ): Observable;
/**
* Create new replication rule.
*
@@ -146,7 +159,7 @@ export abstract class ReplicationService {
*
* @memberOf ReplicationService
*/
- abstract getJobs(
+ abstract getExecutions(
ruleId: number | string,
queryParams?: RequestQueryParams
): Observable | Promise | ReplicationJob;
@@ -165,7 +178,7 @@ export abstract class ReplicationService {
abstract stopJobs(
jobId: number | string
- ): Observable | Promise | string;
+ ): Observable;
abstract getJobBaseUrl(): string;
}
@@ -180,7 +193,6 @@ export abstract class ReplicationService {
@Injectable()
export class ReplicationDefaultService extends ReplicationService {
_ruleBaseUrl: string;
- _jobBaseUrl: string;
_replicateUrl: string;
constructor(
@@ -190,13 +202,10 @@ export class ReplicationDefaultService extends ReplicationService {
super();
this._ruleBaseUrl = config.replicationRuleEndpoint
? config.replicationRuleEndpoint
- : "/api/policies/replication";
- this._jobBaseUrl = config.replicationJobEndpoint
- ? config.replicationJobEndpoint
- : "/api/jobs/replication";
+ : "/api/replication/policies";
this._replicateUrl = config.replicationBaseEndpoint
? config.replicationBaseEndpoint
- : "/api/replications";
+ : "/api/replication/executions";
}
// Private methods
@@ -212,7 +221,7 @@ export class ReplicationDefaultService extends ReplicationService {
}
public getJobBaseUrl() {
- return this._jobBaseUrl;
+ return this._replicateUrl;
}
public getReplicationRules(
@@ -257,6 +266,19 @@ export class ReplicationDefaultService extends ReplicationService {
.catch(error => Promise.reject(error));
}
+ public getReplicationTasks(
+ executionId: number | string
+ ): Observable {
+ if (!executionId) {
+ return observableThrowError("Bad argument");
+ }
+ let url: string = `${this._replicateUrl}/${executionId}/tasks`;
+ return this.http
+ .get(url, HTTP_GET_OPTIONS)
+ .pipe(map (response => response.json() as ReplicationTasks)
+ , catchError(error => observableThrowError(error)));
+ }
+
public createReplicationRule(
replicationRule: ReplicationRule
): Observable | Promise | any {
@@ -352,7 +374,7 @@ export class ReplicationDefaultService extends ReplicationService {
.catch(error => Promise.reject(error));
}
- public getJobs(
+ public getExecutions(
ruleId: number | string,
queryParams?: RequestQueryParams
): Observable | Promise | ReplicationJob {
@@ -366,7 +388,7 @@ export class ReplicationDefaultService extends ReplicationService {
queryParams.set("policy_id", "" + ruleId);
return this.http
- .get(this._jobBaseUrl, buildHttpRequestOptions(queryParams))
+ .get(this._replicateUrl, buildHttpRequestOptions(queryParams))
.toPromise()
.then(response => {
let result: ReplicationJob = {
@@ -401,7 +423,7 @@ export class ReplicationDefaultService extends ReplicationService {
return Promise.reject("Bad argument");
}
- let logUrl = `${this._jobBaseUrl}/${jobId}/log`;
+ let logUrl = `${this._replicateUrl}/${jobId}/log`;
return this.http
.get(logUrl, HTTP_GET_OPTIONS)
.toPromise()
@@ -412,14 +434,16 @@ export class ReplicationDefaultService extends ReplicationService {
public stopJobs(
jobId: number | string
): Observable | Promise | any {
+ if (!jobId || jobId <= 0) {
+ return observableThrowError("Bad request argument.");
+ }
+ let requestUrl: string = `${this._replicateUrl}/${jobId}`;
return this.http
.put(
- this._jobBaseUrl,
- JSON.stringify({ policy_id: jobId, status: "stop" }),
+ requestUrl,
HTTP_JSON_OPTIONS
)
- .toPromise()
- .then(response => response)
- .catch(error => Promise.reject(error));
+ .pipe(map(response => response)
+ , catchError(error => observableThrowError(error)));
}
}
diff --git a/src/portal/lib/src/shared/shared.const.ts b/src/portal/lib/src/shared/shared.const.ts
index f180073ad..ca088f502 100644
--- a/src/portal/lib/src/shared/shared.const.ts
+++ b/src/portal/lib/src/shared/shared.const.ts
@@ -43,7 +43,8 @@ export const enum ConfirmationTargets {
CONFIG_ROUTE,
CONFIG_TAB,
HELM_CHART,
- HELM_CHART_VERSION
+ HELM_CHART_VERSION,
+ STOP_EXECUTIONS
}
export const enum ActionType {
@@ -69,7 +70,7 @@ export const enum ConfirmationState {
}
export const enum ConfirmationButtons {
- CONFIRM_CANCEL, YES_NO, DELETE_CANCEL, CLOSE, REPLICATE_CANCEL
+ CONFIRM_CANCEL, YES_NO, DELETE_CANCEL, CLOSE, REPLICATE_CANCEL, STOP_CANCEL
}
export const LabelColor = [
diff --git a/src/portal/src/app/harbor-routing.module.ts b/src/portal/src/app/harbor-routing.module.ts
index 4ec78ac7e..e7b3170e4 100644
--- a/src/portal/src/app/harbor-routing.module.ts
+++ b/src/portal/src/app/harbor-routing.module.ts
@@ -30,6 +30,8 @@ import { ResetPasswordComponent } from './account/password-setting/reset-passwor
import { GroupComponent } from './group/group.component';
import { TotalReplicationPageComponent } from './replication/total-replication/total-replication-page.component';
+import { ReplicationTasksPageComponent } from './replication/replication-tasks-page/replication-tasks-page.component';
+
import { DestinationPageComponent } from './replication/destination/destination-page.component';
import { ReplicationPageComponent } from './replication/replication-page.component';
@@ -99,6 +101,12 @@ const harborRoutes: Routes = [
canActivate: [SystemAdminGuard],
canActivateChild: [SystemAdminGuard],
},
+ {
+ path: 'replications/:id/:tasks',
+ component: ReplicationTasksPageComponent,
+ canActivate: [SystemAdminGuard],
+ canActivateChild: [SystemAdminGuard],
+ },
{
path: 'tags/:id/:repo',
component: TagRepositoryComponent,
diff --git a/src/portal/src/app/replication/replication-tasks-page/replication-tasks-page.component.html b/src/portal/src/app/replication/replication-tasks-page/replication-tasks-page.component.html
new file mode 100644
index 000000000..0f398b936
--- /dev/null
+++ b/src/portal/src/app/replication/replication-tasks-page/replication-tasks-page.component.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/portal/src/app/replication/replication-tasks-page/replication-tasks-page.component.scss b/src/portal/src/app/replication/replication-tasks-page/replication-tasks-page.component.scss
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/portal/src/app/replication/replication-tasks-page/replication-tasks-page.component.spec.ts b/src/portal/src/app/replication/replication-tasks-page/replication-tasks-page.component.spec.ts
new file mode 100644
index 000000000..1c44388f3
--- /dev/null
+++ b/src/portal/src/app/replication/replication-tasks-page/replication-tasks-page.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ReplicationTasksPageComponent } from './replication-tasks-page.component';
+
+describe('ReplicationTasksPageComponent', () => {
+ let component: ReplicationTasksPageComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ ReplicationTasksPageComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ReplicationTasksPageComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/portal/src/app/replication/replication-tasks-page/replication-tasks-page.component.ts b/src/portal/src/app/replication/replication-tasks-page/replication-tasks-page.component.ts
new file mode 100644
index 000000000..83fe8b6d5
--- /dev/null
+++ b/src/portal/src/app/replication/replication-tasks-page/replication-tasks-page.component.ts
@@ -0,0 +1,18 @@
+import { Component, OnInit } from '@angular/core';
+import { ActivatedRoute } from '@angular/router';
+@Component({
+ selector: 'app-replication-tasks-page',
+ templateUrl: './replication-tasks-page.component.html',
+ styleUrls: ['./replication-tasks-page.component.scss']
+})
+export class ReplicationTasksPageComponent implements OnInit {
+ executionId: string;
+ constructor(
+ private route: ActivatedRoute,
+ ) { }
+
+ ngOnInit(): void {
+ this.executionId = this.route.snapshot.params["id"];
+ }
+
+}
diff --git a/src/portal/src/app/replication/replication.module.ts b/src/portal/src/app/replication/replication.module.ts
index 841110a71..76531a553 100644
--- a/src/portal/src/app/replication/replication.module.ts
+++ b/src/portal/src/app/replication/replication.module.ts
@@ -18,6 +18,7 @@ import { ReplicationManagementComponent } from './replication-management/replica
import { ReplicationPageComponent } from './replication-page.component';
import { TotalReplicationPageComponent } from './total-replication/total-replication-page.component';
import { DestinationPageComponent } from './destination/destination-page.component';
+import { ReplicationTasksPageComponent } from './replication-tasks-page/replication-tasks-page.component';
import { SharedModule } from '../shared/shared.module';
import {ReactiveFormsModule} from "@angular/forms";
@@ -32,11 +33,13 @@ import {ReactiveFormsModule} from "@angular/forms";
ReplicationPageComponent,
ReplicationManagementComponent,
TotalReplicationPageComponent,
+ ReplicationTasksPageComponent,
DestinationPageComponent,
],
exports: [
ReplicationPageComponent,
DestinationPageComponent,
+ ReplicationTasksPageComponent,
TotalReplicationPageComponent,
]
})
diff --git a/src/portal/src/app/shared/shared.module.ts b/src/portal/src/app/shared/shared.module.ts
index 08e7310ab..36ee422e1 100644
--- a/src/portal/src/app/shared/shared.module.ts
+++ b/src/portal/src/app/shared/shared.module.ts
@@ -62,10 +62,9 @@ const uiLibConfig: IServiceConfig = {
systemInfoEndpoint: "/api/systeminfo",
repositoryBaseEndpoint: "/api/repositories",
logBaseEndpoint: "/api/logs",
- targetBaseEndpoint: "/api/targets",
- replicationBaseEndpoint: "/api/replications",
- replicationRuleEndpoint: "/api/policies/replication",
- replicationJobEndpoint: "/api/jobs/replication",
+ targetBaseEndpoint: "/api/registries",
+ replicationBaseEndpoint: "/api/replication/executions",
+ replicationRuleEndpoint: "/api/replication/policies",
vulnerabilityScanningBaseEndpoint: "/api/repositories",
projectPolicyEndpoint: "/api/projects/configs",
projectBaseEndpoint: "/api/projects",
diff --git a/src/portal/src/i18n/lang/en-us-lang.json b/src/portal/src/i18n/lang/en-us-lang.json
index 36f8e1d65..4eafd0c3f 100644
--- a/src/portal/src/i18n/lang/en-us-lang.json
+++ b/src/portal/src/i18n/lang/en-us-lang.json
@@ -17,6 +17,7 @@
"TITLE": "Sign Up"
},
"BUTTON": {
+ "STOP": "STOP",
"CANCEL": "CANCEL",
"OK": "OK",
"DELETE": "DELETE",
@@ -330,6 +331,18 @@
"OF": "of"
},
"REPLICATION": {
+ "STOP_TITLE": "Confirm Stop Executions",
+ "STOP_SUMMARY": "Do you want to stop the executions {{param}}?",
+ "TASK_ID":"Task ID",
+ "RECOURCE_TYPE": "Recource Type",
+ "RECOURCE": "Recource",
+ "DESTINATION": "Destination",
+ "POLICY": "Policy",
+ "DURATION": "Duration",
+ "SUCCESS_RATE": "Success Rate",
+ "SUCCESS": "Success",
+ "FAILTURE": "Failture",
+ "IN_PROGRESS": "In Progress",
"REPLICATION_RULE": "Replication Rule",
"NEW_REPLICATION_RULE": "New Replication Rule",
"ENDPOINTS": "Endpoints",
@@ -353,13 +366,16 @@
"TESTING_CONNECTION": "Testing Connection...",
"TEST_CONNECTION_SUCCESS": "Connection tested successfully.",
"TEST_CONNECTION_FAILURE": "Failed to ping endpoint.",
+ "ID":"ID",
"NAME": "Name",
- "PROJECT": "Project",
"NAME_IS_REQUIRED": "Name is required.",
"DESCRIPTION": "Description",
"ENABLE": "Enable",
"DISABLE": "Disable",
- "DESTINATION_NAME": "Endpoint Name",
+ "REPLICATION_MODE": "Replication Mode",
+ "SRC_NAMESPACE": "Source registry:Namespace",
+ "DESTINATION_NAMESPACE": "Destination registry:Namespace",
+ "LAST_REPLICATION":"Last Replication",
"DESTINATION_NAME_IS_REQUIRED": "Endpoint name is required.",
"NEW_DESTINATION": "New Endpoint",
"DESTINATION_URL": "Endpoint URL",
@@ -371,8 +387,9 @@
"DISABLED": "Disabled",
"LAST_START_TIME": "Last Start Time",
"ACTIVATION": "Activation",
- "REPLICATION_JOBS": "Replication Jobs",
- "STOPJOB": "Stop Jobs",
+ "REPLICATION_EXECUTION": "Execution",
+ "REPLICATION_EXECUTIONS": "Executions",
+ "STOPJOB": "Stop",
"ALL": "All",
"PENDING": "Pending",
"RUNNING": "Running",
@@ -384,9 +401,10 @@
"SIMPLE": "Simple",
"ADVANCED": "Advanced",
"STATUS": "Status",
- "OPERATION": "Operation",
+ "REPLICATION_TRIGGER": "Trigger",
"CREATION_TIME": "Start Time",
"UPDATE_TIME": "Update Time",
+ "END_TIME": "End Time",
"LOGS": "Logs",
"OF": "of",
"ITEMS": "items",
@@ -840,6 +858,7 @@
"ALL": "All",
"RUNNING": "Running",
"FAILED": "Failed",
+ "STOP_EXECUTIONS": "Stop Execution",
"DELETE_PROJECT": "Delete project",
"DELETE_REPO": "Delete repository",
"DELETE_TAG": "Delete tag",
diff --git a/src/portal/src/i18n/lang/es-es-lang.json b/src/portal/src/i18n/lang/es-es-lang.json
index 776694506..a789b0b43 100644
--- a/src/portal/src/i18n/lang/es-es-lang.json
+++ b/src/portal/src/i18n/lang/es-es-lang.json
@@ -17,6 +17,7 @@
"TITLE": "Registrarse"
},
"BUTTON": {
+ "STOP": "STOP",
"CANCEL": "CANCELAR",
"OK": "OK",
"DELETE": "ELIMINAR",
@@ -329,6 +330,20 @@
"OF": "of"
},
"REPLICATION": {
+ "STOP_TITLE": "Confirme Stop Executions",
+ "STOP_SUMMARY": "De que desea detener las ejecuciones {{param}}?",
+ "TASK_ID":"Task ID",
+ "RECOURCE_TYPE": "Recource Type",
+ "RECOURCE": "Recource",
+ "DESTINATION": "Destination",
+ "POLICY": "Policy",
+ "DURATION": "Duration",
+ "SUCCESS_RATE": "Success Rate",
+ "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",
@@ -358,7 +373,10 @@
"DESCRIPTION": "Descripción",
"ENABLE": "Activar",
"DISABLE": "Desactivar",
- "DESTINATION_NAME": "Nombre del Endpoint",
+ "REPLICATION_MODE": "Replication Mode",
+ "SRC_NAMESPACE": "Source registry:Namespace",
+ "DESTINATION_NAMESPACE": "Destination registry:Namespace",
+ "LAST_REPLICATION":"Last Replication",
"DESTINATION_NAME_IS_REQUIRED": "El nombre del endpoint es obligatorio.",
"NEW_DESTINATION": "Nuevo Endpoint",
"DESTINATION_URL": "URL del Endpoint",
@@ -370,8 +388,10 @@
"DISABLED": "Desactivado",
"LAST_START_TIME": "Última Fecha de Inicio",
"ACTIVATION": "Activación",
- "REPLICATION_JOBS": "Trabajos de Replicación",
- "STOPJOB": "Stop Jobs",
+ "REPLICATION_EXECUTION": "Trabajo de Replicación",
+ "REPLICATION_EXECUTIONS": "Trabajos de Replicación",
+ "END_TIME": "End Time",
+ "STOPJOB": "Stop",
"ALL": "Todos",
"PENDING": "Pendiente",
"RUNNING": "Ejecutando",
diff --git a/src/portal/src/i18n/lang/fr-fr-lang.json b/src/portal/src/i18n/lang/fr-fr-lang.json
index 2a4b19715..bcc7ecf0d 100644
--- a/src/portal/src/i18n/lang/fr-fr-lang.json
+++ b/src/portal/src/i18n/lang/fr-fr-lang.json
@@ -17,6 +17,7 @@
"TITLE": "S'inscrire"
},
"BUTTON": {
+ "STOP": "STOP",
"CANCEL": "ANNULER",
"OK": "OK",
"DELETE": "SUPPRIMER",
@@ -314,6 +315,20 @@
"OF": "de"
},
"REPLICATION": {
+ "STOP_TITLE": "Confirmer arrêter les exécutions",
+ "STOP_SUMMARY": "Voulez-vous arrêter les exécutions {{param}}?",
+ "TASK_ID":"Task ID",
+ "RECOURCE_TYPE": "Recource Type",
+ "RECOURCE": "Recource",
+ "DESTINATION": "Destination",
+ "POLICY": "Policy",
+ "DURATION": "Duration",
+ "SUCCESS_RATE": "Success Rate",
+ "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",
@@ -340,7 +355,10 @@
"DESCRIPTION": "Description",
"ENABLE": "Activer",
"DISABLE": "Désactiver",
- "DESTINATION_NAME": "Nom du Point Final",
+ "REPLICATION_MODE": "Replication Mode",
+ "SRC_NAMESPACE": "Source registry:Namespace",
+ "DESTINATION_NAMESPACE": "Destination registry:Namespace",
+ "LAST_REPLICATION":"Last Replication",
"DESTINATION_NAME_IS_REQUIRED": "Le nom du Point Final est obligatoire.",
"NEW_DESTINATION": "Nouveau Point Final",
"DESTINATION_URL": "URL du Point Final",
@@ -352,8 +370,10 @@
"DISABLED": "Désactivé",
"LAST_START_TIME": "Dernière heure de démarrage",
"ACTIVATION": "Activation",
- "REPLICATION_JOBS": "Travaux de Réplication",
+ "REPLICATION_EXECUTION": "Travaux de Réplication",
+ "REPLICATION_EXECUTIONS": "Travaux de Réplication",
"ALL": "Tous",
+ "END_TIME": "End Time",
"PENDING": "En attente",
"RUNNING": "En fonctionnement",
"ERROR": "Erreur",
diff --git a/src/portal/src/i18n/lang/pt-br-lang.json b/src/portal/src/i18n/lang/pt-br-lang.json
index 8ad4c5c83..f1fc885f2 100644
--- a/src/portal/src/i18n/lang/pt-br-lang.json
+++ b/src/portal/src/i18n/lang/pt-br-lang.json
@@ -17,6 +17,7 @@
"TITLE": "Registrar-se"
},
"BUTTON": {
+ "STOP": "STOP",
"CANCEL": "CANCELAR",
"OK": "OK",
"DELETE": "DELETAR",
@@ -328,6 +329,20 @@
"OF": "de"
},
"REPLICATION": {
+ "STOP_TITLE": "Confirme as execuções de parada",
+ "STOP_SUMMARY": "Você quer parar as execuções? {{param}}?",
+ "TASK_ID":"Task ID",
+ "RECOURCE_TYPE": "Recource Type",
+ "RECOURCE": "Recource",
+ "DESTINATION": "Destination",
+ "POLICY": "Policy",
+ "DURATION": "Duration",
+ "SUCCESS_RATE": "Success Rate",
+ "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",
@@ -357,7 +372,10 @@
"DESCRIPTION": "Descrição",
"ENABLE": "Habilitar",
"DISABLE": "Desabilitar",
- "DESTINATION_NAME": "Nome do Endpoint",
+ "REPLICATION_MODE": "Replication Mode",
+ "SRC_NAMESPACE": "Source registry:Namespace",
+ "DESTINATION_NAMESPACE": "Destination registry:Namespace",
+ "LAST_REPLICATION":"Last Replication",
"DESTINATION_NAME_IS_REQUIRED": "Nome do Endpoint é obrigatório.",
"NEW_DESTINATION": "Novo Endpoint",
"DESTINATION_URL": "URL do Endpoint",
@@ -369,8 +387,10 @@
"DISABLED": "Desabilitado",
"LAST_START_TIME": "Ultima hora de início",
"ACTIVATION": "Ativação",
- "REPLICATION_JOBS": "Tarefas de Replicação",
- "STOPJOB": "Parar tarefas",
+ "REPLICATION_EXECUTION": "ExecTarefa de Replicaçãoution",
+ "REPLICATION_EXECUTIONS": "Tarefas de Replicação",
+ "STOPJOB": "Parar",
+ "END_TIME": "End Time",
"ALL": "Todas",
"PENDING": "Pendentes",
"RUNNING": "Executando",
diff --git a/src/portal/src/i18n/lang/zh-cn-lang.json b/src/portal/src/i18n/lang/zh-cn-lang.json
index ee829b758..18a784fc0 100644
--- a/src/portal/src/i18n/lang/zh-cn-lang.json
+++ b/src/portal/src/i18n/lang/zh-cn-lang.json
@@ -17,6 +17,7 @@
"TITLE": "注册"
},
"BUTTON": {
+ "STOP": "停止",
"CANCEL": "取消",
"OK": "确定",
"DELETE": "删除",
@@ -329,6 +330,20 @@
"OF": "共计"
},
"REPLICATION": {
+ "STOP_TITLE": "确认停止任务",
+ "STOP_SUMMARY": "确认停止任务{{param}}?",
+ "TASK_ID":"任务ID",
+ "RECOURCE_TYPE": "源类型",
+ "RECOURCE": "源",
+ "DESTINATION": "目标",
+ "POLICY": "政策",
+ "DURATION": "到期时间",
+ "SUCCESS_RATE": "成功百分比",
+ "SUCCESS": "成功",
+ "FAILTURE": "失败",
+ "IN_PROGRESS": "进行中",
+ "STOP_EXECUTIONS": "停止任务",
+ "ID":"ID",
"REPLICATION_RULE": "复制规则",
"NEW_REPLICATION_RULE": "新建规则",
"ENDPOINTS": "目标",
@@ -358,7 +373,10 @@
"DESCRIPTION": "描述",
"ENABLE": "启用",
"DISABLE": "停用",
- "DESTINATION_NAME": "目标名",
+ "REPLICATION_MODE": "复制模式",
+ "SRC_NAMESPACE": "源仓库:命名空间",
+ "DESTINATION_NAMESPACE": "目标仓库:命名空间",
+ "LAST_REPLICATION":"最后一次复制",
"DESTINATION_NAME_IS_REQUIRED": "目标名称为必填项。",
"NEW_DESTINATION": "创建目标",
"DESTINATION_URL": "目标URL",
@@ -370,7 +388,8 @@
"DISABLED": "停用",
"LAST_START_TIME": "上次起始时间",
"ACTIVATION": "活动状态",
- "REPLICATION_JOBS": "复制任务",
+ "REPLICATION_EXECUTION": "复制任务",
+ "REPLICATION_EXECUTIONS": "复制任务",
"STOPJOB": "停止任务",
"ALL": "全部",
"PENDING": "挂起",
@@ -386,6 +405,7 @@
"OPERATION": "操作",
"CREATION_TIME": "创建时间",
"UPDATE_TIME": "更新时间",
+ "END_TIME": "结束时间",
"LOGS": "日志",
"OF": "共计",
"ITEMS": "条记录",