Improve replication policy datagrid (#16806)

Signed-off-by: AllForNothing <sshijun@vmware.com>
This commit is contained in:
Shijun Sun 2022-05-05 17:36:11 +08:00 committed by GitHub
parent 16f38bc591
commit 584245ec4d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 614 additions and 618 deletions

View File

@ -22,3 +22,7 @@ export enum BandwidthUnit {
MB = 'Mbps', MB = 'Mbps',
KB = 'Kbps' KB = 'Kbps'
} }
export enum ReplicationExecutionFilter {
TRIGGER = 'trigger',
STATUS = 'status'
}

View File

@ -6,7 +6,6 @@ import { DatePickerComponent } from "../../../../../shared/components/datetime-p
import { FilterComponent } from "../../../../../shared/components/filter/filter.component"; import { FilterComponent } from "../../../../../shared/components/filter/filter.component";
import { InlineAlertComponent } from "../../../../../shared/components/inline-alert/inline-alert.component"; import { InlineAlertComponent } from "../../../../../shared/components/inline-alert/inline-alert.component";
import { import {
ReplicationRule,
ReplicationJob, ReplicationJob,
ReplicationJobItem ReplicationJobItem
} from "../../../../../shared/services"; } from "../../../../../shared/services";
@ -21,15 +20,16 @@ import {delay} from "rxjs/operators";
import { SharedTestingModule } from "../../../../../shared/shared.module"; import { SharedTestingModule } from "../../../../../shared/shared.module";
import { RegistryService } from "../../../../../../../ng-swagger-gen/services/registry.service"; import { RegistryService } from "../../../../../../../ng-swagger-gen/services/registry.service";
import { Registry } from "../../../../../../../ng-swagger-gen/models/registry"; import { Registry } from "../../../../../../../ng-swagger-gen/models/registry";
import { ReplicationPolicy } from '../../../../../../../ng-swagger-gen/models/replication-policy';
describe("CreateEditRuleComponent (inline template)", () => { describe("CreateEditRuleComponent (inline template)", () => {
let mockRules: ReplicationRule[] = [ let mockRules: ReplicationPolicy[] = [
{ {
id: 1, id: 1,
name: "sync_01", name: "sync_01",
description: "", description: "",
src_registry: {id: 2}, src_registry: {id: 2},
src_namespaces: ["name1", "name2"], dest_namespace: "",
trigger: { trigger: {
type: "Manual", type: "Manual",
trigger_settings: {} trigger_settings: {}
@ -137,11 +137,11 @@ describe("CreateEditRuleComponent (inline template)", () => {
} }
]; ];
let mockRule: ReplicationRule = { let mockRule: ReplicationPolicy = {
id: 1, id: 1,
name: "sync_01", name: "sync_01",
description: "", description: "",
src_namespaces: ["namespace1", "namespace2"], dest_namespace: "",
src_registry: {id: 10 }, src_registry: {id: 10 },
dest_registry: {id: 0 }, dest_registry: {id: 0 },
trigger: { trigger: {

View File

@ -20,7 +20,7 @@ import {
EventEmitter, EventEmitter,
Output Output
} from "@angular/core"; } from "@angular/core";
import { Filter, ReplicationRule } from "../../../../../shared/services"; import { Filter } from "../../../../../shared/services";
import { forkJoin, Observable, Subject, Subscription } from "rxjs"; import { forkJoin, Observable, Subject, Subscription } from "rxjs";
import { debounceTime, distinctUntilChanged, finalize } from "rxjs/operators"; import { debounceTime, distinctUntilChanged, finalize } from "rxjs/operators";
import { FormArray, FormBuilder, FormGroup, Validators, FormControl } from "@angular/forms"; import { FormArray, FormBuilder, FormGroup, Validators, FormControl } from "@angular/forms";
@ -37,6 +37,7 @@ import { Label } from "../../../../../../../ng-swagger-gen/models/label";
import { LabelService } from "../../../../../../../ng-swagger-gen/services/label.service"; import { LabelService } from "../../../../../../../ng-swagger-gen/services/label.service";
import { BandwidthUnit, Decoration, Flatten_I18n_MAP, Flatten_Level } from "../../replication"; import { BandwidthUnit, Decoration, Flatten_I18n_MAP, Flatten_Level } from "../../replication";
import { errorHandler as errorHandlerFn} from '../../../../../shared/units/shared.utils'; import { errorHandler as errorHandlerFn} from '../../../../../shared/units/shared.utils';
import { ReplicationPolicy } from '../../../../../../../ng-swagger-gen/models/replication-policy';
const PREFIX: string = '0 '; const PREFIX: string = '0 ';
const PAGE_SIZE: number = 100; const PAGE_SIZE: number = 100;
@ -71,7 +72,7 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
policyId: number; policyId: number;
confirmSub: Subscription; confirmSub: Subscription;
ruleForm: FormGroup; ruleForm: FormGroup;
copyUpdateForm: ReplicationRule; copyUpdateForm: ReplicationPolicy;
cronString: string; cronString: string;
supportedTriggers: string[]; supportedTriggers: string[];
supportedFilters: Filter[]; supportedFilters: Filter[];
@ -292,7 +293,7 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
} }
updateRuleFormAndCopyUpdateForm(rule: ReplicationRule): void { updateRuleFormAndCopyUpdateForm(rule: ReplicationPolicy): void {
this.isPushMode = rule.dest_registry.id !== 0; this.isPushMode = rule.dest_registry.id !== 0;
setTimeout(() => { setTimeout(() => {
// convert speed unit to KB or MB // convert speed unit to KB or MB
@ -407,7 +408,7 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
} }
// add new Replication rule // add new Replication rule
this.inProgress = true; this.inProgress = true;
let copyRuleForm: ReplicationRule = this.ruleForm.value; let copyRuleForm: ReplicationPolicy = this.ruleForm.value;
// need to convert unit to KB for speed property // need to convert unit to KB for speed property
copyRuleForm.speed = this.convertToKB(copyRuleForm.speed); copyRuleForm.speed = this.convertToKB(copyRuleForm.speed);
copyRuleForm.dest_namespace_replace_count = copyRuleForm.dest_namespace_replace_count copyRuleForm.dest_namespace_replace_count = copyRuleForm.dest_namespace_replace_count
@ -457,7 +458,7 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
}); });
} }
} }
openCreateEditRule(rule?: ReplicationRule): void { openCreateEditRule(rule?: ReplicationPolicy): void {
this.formReset(); this.formReset();
this.copyUpdateForm = clone(this.ruleForm.value); this.copyUpdateForm = clone(this.ruleForm.value);
this.inlineAlert.close(); this.inlineAlert.close();
@ -474,8 +475,8 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
this.supportedFilterLabels.forEach((label, index) => { this.supportedFilterLabels.forEach((label, index) => {
if (rule.filters && rule.filters.length) { if (rule.filters && rule.filters.length) {
rule.filters.forEach(f => { rule.filters.forEach(f => {
if (f.type === FilterType.LABEL && f.value && f.value.length) { if (f.type === FilterType.LABEL && f.value && (f.value as any).length) {
f.value.forEach(name => { (f.value as any).forEach(name => {
if (label.name === name) { if (label.name === name) {
this.supportedFilterLabels[index].select = true; this.supportedFilterLabels[index].select = true;
} }

View File

@ -2,7 +2,7 @@
<clr-datagrid (clrDgRefresh)="clrLoad($event)" [clrDgLoading]="loading" [(clrDgSingleSelected)]="selectedRow" (clrDgSingleSelectedChange)="selectRule($event)"> <clr-datagrid (clrDgRefresh)="clrLoad($event)" [clrDgLoading]="loading" [(clrDgSingleSelected)]="selectedRow" (clrDgSingleSelectedChange)="selectRule($event)">
<clr-dg-action-bar> <clr-dg-action-bar>
<button type="button" id="new_replication_rule_id" class="btn btn-secondary" *ngIf="hasCreateReplicationPermission" (click)="openModal()"><clr-icon shape="plus" size="16"></clr-icon>&nbsp;{{'REPLICATION.NEW_REPLICATION_RULE' | translate}}</button> <button type="button" id="new_replication_rule_id" class="btn btn-secondary" *ngIf="hasCreateReplicationPermission" (click)="openModal()"><clr-icon shape="plus" size="16"></clr-icon>&nbsp;{{'REPLICATION.NEW_REPLICATION_RULE' | translate}}</button>
<button type="button" id="replication_exe_id" class="btn btn-secondary" *ngIf="hasExecuteReplicationPermission" [disabled]="!selectedRow" (click)="replicateRule(selectedRow)"><clr-icon shape="export" size="16"></clr-icon>&nbsp;{{'REPLICATION.REPLICATE' | translate}}</button> <button type="button" id="replication_exe_id" class="btn btn-secondary" *ngIf="hasExecuteReplicationPermission" [disabled]="!selectedRow || !selectedRow.enabled" (click)="replicateRule(selectedRow)"><clr-icon shape="export" size="16"></clr-icon>&nbsp;{{'REPLICATION.REPLICATE' | translate}}</button>
<clr-dropdown <clr-dropdown
[clrCloseMenuOnItemClick]="false" [clrCloseMenuOnItemClick]="false"
class="btn btn-link" class="btn btn-link"
@ -47,7 +47,7 @@
<clr-dg-column class="col-width">{{'REPLICATION.REPLICATION_MODE' | translate}}</clr-dg-column> <clr-dg-column class="col-width">{{'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>
<clr-dg-column>{{'REPLICATION.DES_REPO_FLATTENING' | translate}}</clr-dg-column> <clr-dg-column>{{'REPLICATION.DES_REPO_FLATTENING' | translate}}</clr-dg-column>
<clr-dg-column [clrDgField]="'trigger'">{{'REPLICATION.REPLICATION_TRIGGER' | translate}}</clr-dg-column> <clr-dg-column>{{'REPLICATION.REPLICATION_TRIGGER' | translate}}</clr-dg-column>
<clr-dg-column [clrDgSortBy]="'speed'">{{'REPLICATION.BANDWIDTH' | translate}}</clr-dg-column> <clr-dg-column [clrDgSortBy]="'speed'">{{'REPLICATION.BANDWIDTH' | translate}}</clr-dg-column>
<clr-dg-column [clrDgField]="'description'">{{'REPLICATION.DESCRIPTION' | 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-placeholder>{{'REPLICATION.PLACEHOLDER' | translate }}</clr-dg-placeholder>

View File

@ -1,27 +1,26 @@
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ConfirmationDialogComponent } from '../../../../../shared/components/confirmation-dialog'; import { ConfirmationDialogComponent } from '../../../../../shared/components/confirmation-dialog';
import { ListReplicationRuleComponent } from './list-replication-rule.component'; import { ListReplicationRuleComponent } from './list-replication-rule.component';
import { ReplicationRule } from '../../../../../shared/services';
import { ErrorHandler } from '../../../../../shared/units/error-handler'; import { ErrorHandler } from '../../../../../shared/units/error-handler';
import { ReplicationService } from '../../../../../shared/services';
import { OperationService } from "../../../../../shared/components/operation/operation.service"; import { OperationService } from "../../../../../shared/components/operation/operation.service";
import { of } from 'rxjs'; import { of } from 'rxjs';
import { delay } from "rxjs/operators"; import { delay } from "rxjs/operators";
import {HttpHeaders, HttpResponse} from "@angular/common/http"; import {HttpHeaders, HttpResponse} from "@angular/common/http";
import { SharedTestingModule } from "../../../../../shared/shared.module"; import { SharedTestingModule } from "../../../../../shared/shared.module";
import { ReplicationPolicy } from '../../../../../../../ng-swagger-gen/models/replication-policy';
import { ReplicationService } from 'ng-swagger-gen/services/replication.service';
describe('ListReplicationRuleComponent (inline template)', () => { describe('ListReplicationRuleComponent (inline template)', () => {
let mockRules: ReplicationRule[] = [ let mockRules: ReplicationPolicy[] = [
{ {
"id": 1, "id": 1,
"name": "sync_01", "name": "sync_01",
"description": "", "description": "",
"filters": null, "filters": null,
"trigger": {"type": "Manual", "trigger_settings": null}, "trigger": {"type": "Manual", "trigger_settings": null},
"error_job_count": 2,
"deletion": false, "deletion": false,
"src_namespaces": ["name1", "name2"], "dest_namespace": "",
"src_registry": {id: 3}, "src_registry": {id: 3},
"enabled": true, "enabled": true,
"override": true, "override": true,
@ -33,9 +32,8 @@ describe('ListReplicationRuleComponent (inline template)', () => {
"description": "", "description": "",
"filters": null, "filters": null,
"trigger": {"type": "Manual", "trigger_settings": null}, "trigger": {"type": "Manual", "trigger_settings": null},
"error_job_count": 2,
"deletion": false, "deletion": false,
"src_namespaces": ["name1", "name2"], "dest_namespace": "",
"dest_registry": {id: 3}, "dest_registry": {id: 3},
"enabled": true, "enabled": true,
"override": true, "override": true,
@ -47,13 +45,13 @@ describe('ListReplicationRuleComponent (inline template)', () => {
let comp: ListReplicationRuleComponent; let comp: ListReplicationRuleComponent;
const fakedReplicationService = { const fakedReplicationService = {
updateReplicationRule() { updateReplicationPolicy() {
return of(true).pipe(delay(0)); return of(true).pipe(delay(0));
}, },
deleteReplicationRule() { deleteReplicationPolicy() {
return of(true).pipe(delay(0)); return of(true).pipe(delay(0));
}, },
getReplicationRulesResponse() { listReplicationPoliciesResponse() {
return of(new HttpResponse({ return of(new HttpResponse({
body: mockRules, body: mockRules,
headers: new HttpHeaders({ headers: new HttpHeaders({

View File

@ -11,28 +11,20 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import { import { Component, EventEmitter, Input, Output, ViewChild, } from "@angular/core";
Component,
Input,
Output,
EventEmitter,
ViewChild,
} from "@angular/core";
import { TranslateService } from "@ngx-translate/core"; import { TranslateService } from "@ngx-translate/core";
import { map, catchError, finalize } from "rxjs/operators"; import { catchError, finalize, map } from "rxjs/operators";
import { Observable, forkJoin, throwError as observableThrowError } from "rxjs"; import { forkJoin, Observable, throwError as observableThrowError } from "rxjs";
import { ReplicationService } from "../../../../../shared/services";
import {
ReplicationRule
} from "../../../../../shared/services";
import { ConfirmationDialogComponent } from "../../../../../shared/components/confirmation-dialog"; import { ConfirmationDialogComponent } from "../../../../../shared/components/confirmation-dialog";
import { import { ConfirmationButtons, ConfirmationState, ConfirmationTargets } from "../../../../../shared/entities/shared.const";
ConfirmationState,
ConfirmationTargets,
ConfirmationButtons
} from "../../../../../shared/entities/shared.const";
import { ErrorHandler } from "../../../../../shared/units/error-handler"; import { ErrorHandler } from "../../../../../shared/units/error-handler";
import { clone, getPageSizeFromLocalStorage, PageSizeMapKeys, setPageSizeToLocalStorage } from "../../../../../shared/units/utils"; import {
clone,
getPageSizeFromLocalStorage, getQueryString,
getSortingString,
PageSizeMapKeys,
setPageSizeToLocalStorage
} from "../../../../../shared/units/utils";
import { operateChanges, OperateInfo, OperationState } from "../../../../../shared/components/operation/operate"; import { operateChanges, OperateInfo, OperationState } from "../../../../../shared/components/operation/operate";
import { OperationService } from "../../../../../shared/components/operation/operation.service"; import { OperationService } from "../../../../../shared/components/operation/operation.service";
import { ClrDatagridStateInterface } from '@clr/angular'; import { ClrDatagridStateInterface } from '@clr/angular';
@ -42,12 +34,15 @@ import { ConfirmationMessage } from "../../../../global-confirmation-dialog/conf
import { HELM_HUB } from "../../../../../shared/services/endpoint.service"; import { HELM_HUB } from "../../../../../shared/services/endpoint.service";
import { BandwidthUnit, Flatten_I18n_MAP } from "../../replication"; import { BandwidthUnit, Flatten_I18n_MAP } from "../../replication";
import { KB_TO_MB } from "../create-edit-rule/create-edit-rule.component"; import { KB_TO_MB } from "../create-edit-rule/create-edit-rule.component";
import { ReplicationService } from "ng-swagger-gen/services/replication.service";
import { ReplicationPolicy } from '../../../../../../../ng-swagger-gen/models/replication-policy';
@Component({ @Component({
selector: "hbr-list-replication-rule", selector: "hbr-list-replication-rule",
templateUrl: "./list-replication-rule.component.html", templateUrl: "./list-replication-rule.component.html",
styleUrls: ["./list-replication-rule.component.scss"], styleUrls: ["./list-replication-rule.component.scss"],
}) })
export class ListReplicationRuleComponent { export class ListReplicationRuleComponent {
@Input() selectedId: number | string; @Input() selectedId: number | string;
@Input() withReplicationJob: boolean; @Input() withReplicationJob: boolean;
@Input() hasCreateReplicationPermission: boolean; @Input() hasCreateReplicationPermission: boolean;
@ -55,15 +50,15 @@ export class ListReplicationRuleComponent {
@Input() hasDeleteReplicationPermission: boolean; @Input() hasDeleteReplicationPermission: boolean;
@Input() hasExecuteReplicationPermission: boolean; @Input() hasExecuteReplicationPermission: boolean;
@Input() searchString: string; @Input() searchString: string;
@Output() selectOne = new EventEmitter<ReplicationRule>(); @Output() selectOne = new EventEmitter<ReplicationPolicy>();
@Output() editOne = new EventEmitter<ReplicationRule>(); @Output() editOne = new EventEmitter<ReplicationPolicy>();
@Output() toggleOne = new EventEmitter<ReplicationRule>(); @Output() toggleOne = new EventEmitter<ReplicationPolicy>();
@Output() hideJobs = new EventEmitter<any>(); @Output() hideJobs = new EventEmitter<any>();
@Output() redirect = new EventEmitter<ReplicationRule>(); @Output() redirect = new EventEmitter<ReplicationPolicy>();
@Output() openNewRule = new EventEmitter<any>(); @Output() openNewRule = new EventEmitter<any>();
@Output() replicateManual = new EventEmitter<ReplicationRule>(); @Output() replicateManual = new EventEmitter<ReplicationPolicy>();
rules: ReplicationRule[] = []; rules: ReplicationPolicy[] = [];
selectedRow: ReplicationRule; selectedRow: ReplicationPolicy;
@ViewChild("toggleConfirmDialog") @ViewChild("toggleConfirmDialog")
toggleConfirmDialog: ConfirmationDialogComponent; toggleConfirmDialog: ConfirmationDialogComponent;
@ViewChild("deletionConfirmDialog") @ViewChild("deletionConfirmDialog")
@ -74,9 +69,9 @@ export class ListReplicationRuleComponent {
loading: boolean = true; loading: boolean = true;
constructor(private replicationService: ReplicationService, constructor(private replicationService: ReplicationService,
private translateService: TranslateService, private translateService: TranslateService,
private errorHandlerEntity: ErrorHandler, private errorHandlerEntity: ErrorHandler,
private operationService: OperationService) { private operationService: OperationService) {
} }
trancatedDescription(desc: string): string { trancatedDescription(desc: string): string {
@ -86,9 +81,11 @@ export class ListReplicationRuleComponent {
return desc; return desc;
} }
} }
replicateRule(rule: ReplicationRule): void {
replicateRule(rule: ReplicationPolicy): void {
this.replicateManual.emit(rule); this.replicateManual.emit(rule);
} }
deletionConfirm(message: ConfirmationAcknowledgement) { deletionConfirm(message: ConfirmationAcknowledgement) {
if ( if (
message && message &&
@ -97,10 +94,10 @@ export class ListReplicationRuleComponent {
) { ) {
this.deleteOpe(message.data); this.deleteOpe(message.data);
} }
if ( message && if (message &&
message.source === ConfirmationTargets.REPLICATION && message.source === ConfirmationTargets.REPLICATION &&
message.state === ConfirmationState.CONFIRMED) { message.state === ConfirmationState.CONFIRMED) {
const rule: ReplicationRule = clone(message.data); const rule: ReplicationPolicy = clone(message.data);
rule.enabled = !message.data.enabled; rule.enabled = !message.data.enabled;
const opeMessage = new OperateInfo(); const opeMessage = new OperateInfo();
opeMessage.name = rule.enabled ? 'REPLICATION.ENABLE_TITLE' : 'REPLICATION.DISABLE_TITLE'; opeMessage.name = rule.enabled ? 'REPLICATION.ENABLE_TITLE' : 'REPLICATION.DISABLE_TITLE';
@ -108,34 +105,38 @@ export class ListReplicationRuleComponent {
opeMessage.state = OperationState.progressing; opeMessage.state = OperationState.progressing;
opeMessage.data.name = rule.name; opeMessage.data.name = rule.name;
this.operationService.publishInfo(opeMessage); this.operationService.publishInfo(opeMessage);
this.replicationService.updateReplicationRule(rule.id, rule).subscribe( this.replicationService.updateReplicationPolicy({
res => { id: rule.id,
policy: rule
}).subscribe({
next: () => {
this.translateService.get(rule.enabled ? 'REPLICATION.ENABLE_SUCCESS' : 'REPLICATION.DISABLE_SUCCESS') this.translateService.get(rule.enabled ? 'REPLICATION.ENABLE_SUCCESS' : 'REPLICATION.DISABLE_SUCCESS')
.subscribe(msg => { .subscribe(msg => {
operateChanges(opeMessage, OperationState.success); operateChanges(opeMessage, OperationState.success);
this.errorHandlerEntity.info(msg); this.errorHandlerEntity.info(msg);
this.refreshRule(); this.refreshRule();
}); });
}, error => { },
error: error => {
const errMessage = errorHandler(error); const errMessage = errorHandler(error);
this.translateService.get(rule.enabled ? 'REPLICATION.ENABLE_FAILED' : 'REPLICATION.DISABLE_FAILED') this.translateService.get(rule.enabled ? 'REPLICATION.ENABLE_FAILED' : 'REPLICATION.DISABLE_FAILED')
.subscribe(msg => { .subscribe(msg => {
operateChanges(opeMessage, OperationState.failure, msg); operateChanges(opeMessage, OperationState.failure, msg);
this.errorHandlerEntity.error(errMessage); this.errorHandlerEntity.error(errMessage);
}); });
} }
); });
} }
} }
selectRule(rule: ReplicationRule): void { selectRule(rule: ReplicationPolicy): void {
if (rule) { if (rule) {
this.selectedId = rule.id || ""; this.selectedId = rule.id || "";
this.selectOne.emit(rule); this.selectOne.emit(rule);
} }
} }
redirectTo(rule: ReplicationRule): void { redirectTo(rule: ReplicationPolicy): void {
this.redirect.emit(rule); this.redirect.emit(rule);
} }
@ -143,11 +144,11 @@ export class ListReplicationRuleComponent {
this.openNewRule.emit(); this.openNewRule.emit();
} }
editRule(rule: ReplicationRule) { editRule(rule: ReplicationPolicy) {
this.editOne.emit(rule); this.editOne.emit(rule);
} }
deleteRule(rule: ReplicationRule) { deleteRule(rule: ReplicationPolicy) {
if (rule) { if (rule) {
let deletionMessage = new ConfirmationMessage( let deletionMessage = new ConfirmationMessage(
"REPLICATION.DELETION_TITLE", "REPLICATION.DELETION_TITLE",
@ -161,7 +162,7 @@ export class ListReplicationRuleComponent {
} }
} }
deleteOpe(rule: ReplicationRule) { deleteOpe(rule: ReplicationPolicy) {
if (rule) { if (rule) {
let observableLists: any[] = []; let observableLists: any[] = [];
observableLists.push(this.delOperate(rule)); observableLists.push(this.delOperate(rule));
@ -175,7 +176,7 @@ export class ListReplicationRuleComponent {
} }
} }
delOperate(rule: ReplicationRule): Observable<any> { delOperate(rule: ReplicationPolicy): Observable<any> {
// init operation info // init operation info
let operMessage = new OperateInfo(); let operMessage = new OperateInfo();
operMessage.name = 'OPERATION.DELETE_REPLICATION'; operMessage.name = 'OPERATION.DELETE_REPLICATION';
@ -185,11 +186,13 @@ export class ListReplicationRuleComponent {
this.operationService.publishInfo(operMessage); this.operationService.publishInfo(operMessage);
return this.replicationService return this.replicationService
.deleteReplicationRule(+rule.id) .deleteReplicationPolicy({
.pipe(map(() => { id: rule.id
this.translateService.get('BATCH.DELETED_SUCCESS')
.subscribe(res => operateChanges(operMessage, OperationState.success));
}) })
.pipe(map(() => {
this.translateService.get('BATCH.DELETED_SUCCESS')
.subscribe(res => operateChanges(operMessage, OperationState.success));
})
, catchError(error => { , catchError(error => {
const message = errorHandler(error); const message = errorHandler(error);
this.translateService.get(message).subscribe(res => this.translateService.get(message).subscribe(res =>
@ -198,7 +201,8 @@ export class ListReplicationRuleComponent {
return observableThrowError(error); return observableThrowError(error);
})); }));
} }
operateRule(operation: string, rule: ReplicationRule): void {
operateRule(operation: string, rule: ReplicationPolicy): void {
let title: string; let title: string;
let summary: string; let summary: string;
let buttons: ConfirmationButtons; let buttons: ConfirmationButtons;
@ -228,32 +232,44 @@ export class ListReplicationRuleComponent {
); );
this.deletionConfirmDialog.open(msg); this.deletionConfirmDialog.open(msg);
} }
clrLoad(state?: ClrDatagridStateInterface) { clrLoad(state?: ClrDatagridStateInterface) {
if (state && state.page) { if (state && state.page) {
this.pageSize = state.page.size; this.pageSize = state.page.size;
setPageSizeToLocalStorage(PageSizeMapKeys.LIST_REPLICATION_RULE_COMPONENT, this.pageSize); setPageSizeToLocalStorage(PageSizeMapKeys.LIST_REPLICATION_RULE_COMPONENT, this.pageSize);
} }
this.loading = true; this.loading = true;
this.replicationService.getReplicationRulesResponse( const param: ReplicationService.ListReplicationPoliciesParams = {
this.searchString, page: this.page,
this.page, pageSize: this.pageSize,
this.pageSize) sort: getSortingString(state),
};
if (this.searchString) {
param.q = encodeURIComponent(`name=~${this.searchString}`);
} else {
param.q = getQueryString(state);
}
this.replicationService.listReplicationPoliciesResponse(param)
.pipe(finalize(() => this.loading = false)) .pipe(finalize(() => this.loading = false))
.subscribe(response => { .subscribe({
// job list hidden next: response => {
this.hideJobs.emit(); // job list hidden
// Get total count this.hideJobs.emit();
if (response.headers) { // Get total count
let xHeader: string = response.headers.get("x-total-count"); if (response.headers) {
if (xHeader) { let xHeader: string = response.headers.get("x-total-count");
this.totalCount = parseInt(xHeader, 0); if (xHeader) {
} this.totalCount = parseInt(xHeader, 0);
} }
this.rules = response.body as ReplicationRule[]; }
}, error => { this.rules = response.body as ReplicationPolicy[];
this.errorHandlerEntity.error(error); },
error: error => {
this.errorHandlerEntity.error(error);
}
}); });
} }
refreshRule() { refreshRule() {
this.page = 1; this.page = 1;
this.totalCount = 0; this.totalCount = 0;
@ -261,15 +277,18 @@ export class ListReplicationRuleComponent {
this.searchString = null; this.searchString = null;
this.clrLoad(); this.clrLoad();
} }
isHelmHub(srcRegistry: any): boolean { isHelmHub(srcRegistry: any): boolean {
return srcRegistry && srcRegistry.type === HELM_HUB; return srcRegistry && srcRegistry.type === HELM_HUB;
} }
getFlattenLevelString(level: number) { getFlattenLevelString(level: number) {
if (level !== null && Flatten_I18n_MAP[level]) { if (level !== null && Flatten_I18n_MAP[level]) {
return Flatten_I18n_MAP[level]; return Flatten_I18n_MAP[level];
} }
return level; return level;
} }
getBandwidthStr(speed: number): string { getBandwidthStr(speed: number): string {
if (speed >= KB_TO_MB) { if (speed >= KB_TO_MB) {
return '' + (speed / KB_TO_MB).toFixed(2) + BandwidthUnit.MB; return '' + (speed / KB_TO_MB).toFixed(2) + BandwidthUnit.MB;

View File

@ -12,7 +12,7 @@
</div> </div>
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12"> <div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
<hbr-list-replication-rule #listReplicationRule (replicateManual)=replicateManualRule($event) <hbr-list-replication-rule #listReplicationRule (replicateManual)=replicateManualRule($event)
(selectOne)="selectOneRule($event)" (hideJobs)="hideJobs()" (openNewRule)="openModal()" (editOne)="openEditRule($event)" [withReplicationJob]="withReplicationJob" (redirect)="customRedirect($event)" (selectOne)="selectOneRule($event)" (hideJobs)="hideJobs()" (openNewRule)="openModal()" (editOne)="openEditRule($event)" [withReplicationJob]="withReplicationJob"
[hasCreateReplicationPermission]="hasCreateReplicationPermission" [hasCreateReplicationPermission]="hasCreateReplicationPermission"
[hasUpdateReplicationPermission]="hasUpdateReplicationPermission" [hasUpdateReplicationPermission]="hasUpdateReplicationPermission"
[hasDeleteReplicationPermission]="hasDeleteReplicationPermission" [hasDeleteReplicationPermission]="hasDeleteReplicationPermission"

View File

@ -4,10 +4,9 @@ import { NoopAnimationsModule } from "@angular/platform-browser/animations";
import { ConfirmationDialogComponent } from '../../../../shared/components/confirmation-dialog'; import { ConfirmationDialogComponent } from '../../../../shared/components/confirmation-dialog';
import { ReplicationComponent } from './replication.component'; import { ReplicationComponent } from './replication.component';
import { CronScheduleComponent } from '../../../../shared/components/cron-schedule'; import { CronScheduleComponent } from '../../../../shared/components/cron-schedule';
import { ReplicationRule, ReplicationJob, Endpoint} from '../../../../shared/services'; import { ReplicationJob, Endpoint} from '../../../../shared/services';
import { CronTooltipComponent } from "../../../../shared/components/cron-schedule"; import { CronTooltipComponent } from "../../../../shared/components/cron-schedule";
import { ErrorHandler } from '../../../../shared/units/error-handler'; import { ErrorHandler } from '../../../../shared/units/error-handler';
import { ReplicationService } from '../../../../shared/services';
import { ReplicationJobItem } from '../../../../shared/services'; import { ReplicationJobItem } from '../../../../shared/services';
import { OperationService } from "../../../../shared/components/operation/operation.service"; import { OperationService } from "../../../../shared/components/operation/operation.service";
import { RouterTestingModule } from '@angular/router/testing'; import { RouterTestingModule } from '@angular/router/testing';
@ -15,21 +14,22 @@ import { of, Subscription } from 'rxjs';
import { HttpHeaders, HttpResponse } from "@angular/common/http"; import { HttpHeaders, HttpResponse } from "@angular/common/http";
import { delay } from "rxjs/operators"; import { delay } from "rxjs/operators";
import { SharedTestingModule } from "../../../../shared/shared.module"; import { SharedTestingModule } from "../../../../shared/shared.module";
import { ReplicationPolicy } from '../../../../../../ng-swagger-gen/models/replication-policy';
import { ReplicationService } from 'ng-swagger-gen/services/replication.service';
describe('Replication Component (inline template)', () => { describe('Replication Component (inline template)', () => {
let mockRules: ReplicationRule[] = [ let mockRules: ReplicationPolicy[] = [
{ {
"id": 1, "id": 1,
"name": "sync_01", "name": "sync_01",
"description": "", "description": "",
"filters": null, "filters": null,
"trigger": {"type": "Manual", "trigger_settings": null}, "trigger": {"type": "Manual", "trigger_settings": null},
"error_job_count": 2,
"deletion": false, "deletion": false,
"src_registry": {id: 3}, "src_registry": {id: 3},
"src_namespaces": ["name1"], "dest_namespace": "",
"enabled": true, "enabled": true,
"override": true, "override": true,
"speed": -1 "speed": -1
@ -40,10 +40,9 @@ describe('Replication Component (inline template)', () => {
"description": "", "description": "",
"filters": null, "filters": null,
"trigger": {"type": "Manual", "trigger_settings": null}, "trigger": {"type": "Manual", "trigger_settings": null},
"error_job_count": 2,
"deletion": false, "deletion": false,
"dest_registry": {id: 5}, "dest_registry": {id: 5},
"src_namespaces": ["name1"], "dest_namespace": "",
"enabled": true, "enabled": true,
"override": true, "override": true,
"speed": -1 "speed": -1
@ -127,7 +126,7 @@ describe('Replication Component (inline template)', () => {
} }
}; };
const fakedReplicationService = { const fakedReplicationService = {
getReplicationRulesResponse() { listReplicationPoliciesResponse() {
return of(new HttpResponse({ return of(new HttpResponse({
body: mockRules, body: mockRules,
headers: new HttpHeaders({ headers: new HttpHeaders({

View File

@ -5,9 +5,8 @@
[isSystemAdmin]="isSystemAdmin" [isSystemAdmin]="isSystemAdmin"
[withAdmiral]="withAdmiral" [withAdmiral]="withAdmiral"
(goToRegistry)="goRegistry()" (goToRegistry)="goRegistry()"
(redirect)="customRedirect($event)"
[hasCreateReplicationPermission]="true" [hasCreateReplicationPermission]="true"
[hasUpdateReplicationPermission]="true" [hasUpdateReplicationPermission]="true"
[hasDeleteReplicationPermission]="true" [hasDeleteReplicationPermission]="true"
[hasExecuteReplicationPermission]="true"></hbr-replication> [hasExecuteReplicationPermission]="true"></hbr-replication>
</div> </div>

View File

@ -15,7 +15,6 @@ import { Component, OnDestroy, OnInit } from '@angular/core';
import { Router, ActivatedRoute, NavigationEnd } from "@angular/router"; import { Router, ActivatedRoute, NavigationEnd } from "@angular/router";
import {SessionService} from "../../../shared/services/session.service"; import {SessionService} from "../../../shared/services/session.service";
import {AppConfigService} from "../../../services/app-config.service"; import {AppConfigService} from "../../../services/app-config.service";
import { ReplicationRule } from "../../../shared/services";
import { Subscription } from "rxjs"; import { Subscription } from "rxjs";
import { EventService, HarborEvent } from "../../../services/event-service/event.service"; import { EventService, HarborEvent } from "../../../services/event-service/event.service";
// The route path which will display this component // The route path which will display this component
@ -64,11 +63,6 @@ export class TotalReplicationPageComponent implements OnInit, OnDestroy {
this.scrollSub = null; this.scrollSub = null;
} }
} }
customRedirect(rule: ReplicationRule): void {
if (rule) {
this.router.navigate(['../projects', rule.projects[0].project_id, 'replications'], { relativeTo: this.activeRoute });
}
}
goRegistry(): void { goRegistry(): void {
this.router.navigate(['harbor', 'registries']); this.router.navigate(['harbor', 'registries']);
} }

View File

@ -7,8 +7,9 @@ import {
HTTP_GET_OPTIONS, CURRENT_BASE_HREF HTTP_GET_OPTIONS, CURRENT_BASE_HREF
} from "../units/utils"; } from "../units/utils";
import { RequestQueryParams } from "./index"; import { RequestQueryParams } from "./index";
import { Endpoint, ReplicationRule, PingEndpoint } from "./index"; import { Endpoint, PingEndpoint } from "./index";
import { catchError, map } from "rxjs/operators"; import { catchError, map } from "rxjs/operators";
import { ReplicationPolicy } from '../../../../ng-swagger-gen/models/replication-policy';
export const ADAPTERS_MAP = { export const ADAPTERS_MAP = {
"ali-acr": "Alibaba ACR", "ali-acr": "Alibaba ACR",
@ -264,7 +265,7 @@ export class EndpointDefaultService extends EndpointService {
let requestUrl: string = `${this._endpointUrl}/${endpointId}/policies`; let requestUrl: string = `${this._endpointUrl}/${endpointId}/policies`;
return this.http return this.http
.get(requestUrl, HTTP_GET_OPTIONS) .get(requestUrl, HTTP_GET_OPTIONS)
.pipe(map(response => response as ReplicationRule[]) .pipe(map(response => response as ReplicationPolicy[])
, catchError(error => observableThrowError(error))); , catchError(error => observableThrowError(error)));
} }

View File

@ -53,32 +53,6 @@ export interface Filter {
values?: string[]; values?: string[];
} }
/**
* Interface for replication rule.
*
**
* interface ReplicationRule
* interface Filter
* interface Trigger
*/
export interface ReplicationRule extends Base {
[key: string]: any;
id?: number;
name: string;
description: string;
trigger: Trigger;
filters: Filter[];
deletion?: boolean;
src_registry?: any;
dest_registry?: any;
src_namespaces: string[];
dest_namespace?: string;
dest_namespace_replace_count?: number;
enabled: boolean;
override: boolean;
speed: number;
}
export class Filter { export class Filter {
type: string; type: string;
value?: any; value?: any;

View File

@ -9,13 +9,13 @@ import {
} from "../units/utils"; } from "../units/utils";
import { import {
ReplicationJob, ReplicationJob,
ReplicationRule,
ReplicationJobItem, ReplicationJobItem,
ReplicationTasks ReplicationTasks
} from "./interface"; } from "./interface";
import { RequestQueryParams } from "./RequestQueryParams"; import { RequestQueryParams } from "./RequestQueryParams";
import { map, catchError } from "rxjs/operators"; import { map, catchError } from "rxjs/operators";
import { Observable, throwError as observableThrowError } from "rxjs"; import { Observable, throwError as observableThrowError } from "rxjs";
import { ReplicationPolicy } from '../../../../ng-swagger-gen/models/replication-policy';
/** /**
* Define the service methods to handle the replication (rule and job) related things. * Define the service methods to handle the replication (rule and job) related things.
@ -44,13 +44,13 @@ export abstract class ReplicationService {
ruleName?: string, ruleName?: string,
queryParams?: RequestQueryParams queryParams?: RequestQueryParams
): ):
| Observable<ReplicationRule[]>; | Observable<ReplicationPolicy[]>;
abstract getReplicationRulesResponse( abstract getReplicationRulesResponse(
ruleName?: string, ruleName?: string,
page?: number , page?: number ,
pageSize?: number, pageSize?: number,
queryParams?: RequestQueryParams queryParams?: RequestQueryParams
): Observable<HttpResponse<ReplicationRule[]>>; ): Observable<HttpResponse<ReplicationPolicy[]>>;
/** /**
* Get the specified replication rule. * Get the specified replication rule.
@ -63,7 +63,7 @@ export abstract class ReplicationService {
*/ */
abstract getReplicationRule( abstract getReplicationRule(
ruleId: number | string ruleId: number | string
): Observable<ReplicationRule>; ): Observable<ReplicationPolicy>;
/** /**
@ -88,7 +88,7 @@ export abstract class ReplicationService {
* @memberOf ReplicationService * @memberOf ReplicationService
*/ */
abstract createReplicationRule( abstract createReplicationRule(
replicationRule: ReplicationRule replicationRule: ReplicationPolicy
): Observable<any>; ): Observable<any>;
/** /**
@ -102,7 +102,7 @@ export abstract class ReplicationService {
*/ */
abstract updateReplicationRule( abstract updateReplicationRule(
id: number, id: number,
rep: ReplicationRule rep: ReplicationPolicy
): Observable<any>; ): Observable<any>;
/** /**
@ -229,7 +229,7 @@ export class ReplicationDefaultService extends ReplicationService {
// Private methods // Private methods
// Check if the rule object is valid // Check if the rule object is valid
_isValidRule(rule: ReplicationRule): boolean { _isValidRule(rule: ReplicationPolicy): boolean {
return ( return (
rule !== undefined && rule !== undefined &&
rule != null && rule != null &&
@ -255,7 +255,7 @@ export class ReplicationDefaultService extends ReplicationService {
ruleName?: string, ruleName?: string,
queryParams?: RequestQueryParams queryParams?: RequestQueryParams
): ):
| Observable<ReplicationRule[]> { | Observable<ReplicationPolicy[]> {
if (!queryParams) { if (!queryParams) {
queryParams = new RequestQueryParams(); queryParams = new RequestQueryParams();
} }
@ -269,14 +269,14 @@ export class ReplicationDefaultService extends ReplicationService {
} }
return this.http return this.http
.get(this._ruleBaseUrl, buildHttpRequestOptions(queryParams)) .get(this._ruleBaseUrl, buildHttpRequestOptions(queryParams))
.pipe(map(response => response as ReplicationRule[]) .pipe(map(response => response as ReplicationPolicy[])
, catchError(error => observableThrowError(error))); , catchError(error => observableThrowError(error)));
} }
public getReplicationRulesResponse( public getReplicationRulesResponse(
ruleName?: string, ruleName?: string,
page?: number, page?: number,
pageSize?: number, pageSize?: number,
queryParams?: RequestQueryParams): Observable<HttpResponse<ReplicationRule[]>> { queryParams?: RequestQueryParams): Observable<HttpResponse<ReplicationPolicy[]>> {
if (!queryParams) { if (!queryParams) {
queryParams = new RequestQueryParams(); queryParams = new RequestQueryParams();
} }
@ -290,14 +290,14 @@ export class ReplicationDefaultService extends ReplicationService {
queryParams = queryParams.set("page_size", pageSize + ""); queryParams = queryParams.set("page_size", pageSize + "");
} }
return this.http return this.http
.get<HttpResponse<ReplicationRule[]>>(this._ruleBaseUrl, buildHttpRequestOptionsWithObserveResponse(queryParams)) .get<HttpResponse<ReplicationPolicy[]>>(this._ruleBaseUrl, buildHttpRequestOptionsWithObserveResponse(queryParams))
.pipe(map(response => response as HttpResponse<ReplicationRule[]>) .pipe(map(response => response as HttpResponse<ReplicationPolicy[]>)
, catchError(error => observableThrowError(error))); , catchError(error => observableThrowError(error)));
} }
public getReplicationRule( public getReplicationRule(
ruleId: number | string ruleId: number | string
): Observable<ReplicationRule> { ): Observable<ReplicationPolicy> {
if (!ruleId) { if (!ruleId) {
return observableThrowError("Bad argument"); return observableThrowError("Bad argument");
} }
@ -305,7 +305,7 @@ export class ReplicationDefaultService extends ReplicationService {
let url: string = `${this._ruleBaseUrl}/${ruleId}`; let url: string = `${this._ruleBaseUrl}/${ruleId}`;
return this.http return this.http
.get(url, HTTP_GET_OPTIONS) .get(url, HTTP_GET_OPTIONS)
.pipe(map(response => response as ReplicationRule) .pipe(map(response => response as ReplicationPolicy)
, catchError(error => observableThrowError(error))); , catchError(error => observableThrowError(error)));
} }
@ -324,7 +324,7 @@ export class ReplicationDefaultService extends ReplicationService {
} }
public createReplicationRule( public createReplicationRule(
replicationRule: ReplicationRule replicationRule: ReplicationPolicy
): Observable<any> { ): Observable<any> {
if (!this._isValidRule(replicationRule)) { if (!this._isValidRule(replicationRule)) {
return observableThrowError("Bad argument"); return observableThrowError("Bad argument");
@ -342,7 +342,7 @@ export class ReplicationDefaultService extends ReplicationService {
public updateReplicationRule( public updateReplicationRule(
id: number, id: number,
rep: ReplicationRule rep: ReplicationPolicy
): Observable<any> { ): Observable<any> {
if (!this._isValidRule(rep)) { if (!this._isValidRule(rep)) {
return observableThrowError("Bad argument"); return observableThrowError("Bad argument");