Update per comments.

This commit is contained in:
kunw 2017-05-22 16:57:28 +08:00
parent 227b440956
commit 5d3ed05a09
14 changed files with 70 additions and 205 deletions

View File

@ -8,7 +8,7 @@ import { ConfirmationDialogComponent } from '../confirmation-dialog/confirmation
import { ReplicationComponent } from '../replication/replication.component';
import { ListReplicationRuleComponent } from '../list-replication-rule/list-replication-rule.component';
import { ListReplicationJobComponent } from '../list-replication-job/list-replication-job.component';
import { CreateEditRuleComponent } from './create-edit-rule.component';
import { DatePickerComponent } from '../datetime-picker/datetime-picker.component';
import { DateValidatorDirective } from '../datetime-picker/date-validator.directive';
@ -88,7 +88,7 @@ describe('CreateEditRuleComponent (inline template)', ()=>{
"repository": "library/busybox",
"policy_id": 2,
"operation": "transfer",
"tags": null
"tags": null
}
];
@ -171,7 +171,6 @@ describe('CreateEditRuleComponent (inline template)', ()=>{
declarations: [
ReplicationComponent,
ListReplicationRuleComponent,
ListReplicationJobComponent,
CreateEditRuleComponent,
ConfirmationDialogComponent,
DatePickerComponent,
@ -188,26 +187,28 @@ describe('CreateEditRuleComponent (inline template)', ()=>{
}));
beforeEach(()=>{
fixture = TestBed.createComponent(ReplicationComponent);
fixtureCreate = TestBed.createComponent(CreateEditRuleComponent);
comp = fixture.componentInstance;
comp.projectId = 1;
comp.search.ruleId = 1;
compCreate = fixtureCreate.componentInstance;
comp.projectId = 1;
replicationService = fixture.debugElement.injector.get(ReplicationService);
endpointService = fixtureCreate.debugElement.injector.get(EndpointService);
spyRules = spyOn(replicationService, 'getReplicationRules').and.returnValues(Promise.resolve(mockRules));
spyOneRule = spyOn(replicationService, 'getReplicationRule').and.returnValue(Promise.resolve(mockRule));
spyJobs = spyOn(replicationService, 'getJobs').and.returnValues(Promise.resolve(mockJobs));
spyEndpoint = spyOn(endpointService, 'getEndpoints').and.returnValues(Promise.resolve(mockEndpoints));
fixture.detectChanges();
});
beforeEach(()=>{
fixtureCreate = TestBed.createComponent(CreateEditRuleComponent);
compCreate = fixtureCreate.componentInstance;
compCreate.projectId = 1;
endpointService = fixtureCreate.debugElement.injector.get(EndpointService);
spyEndpoint = spyOn(endpointService, 'getEndpoints').and.returnValues(Promise.resolve(mockEndpoints));
fixture.detectChanges();
});

View File

@ -208,7 +208,7 @@ export class CreateEditRuleComponent implements AfterViewChecked {
}).catch(err=>this.errorHandler.error(err));
} else {
if(!this.projectId) {
console.error('Project ID cannot be unset');
this.errorHandler.error('Project ID cannot be unset');
return;
}
this.actionType = ActionType.ADD_NEW;
@ -378,12 +378,12 @@ export class CreateEditRuleComponent implements AfterViewChecked {
for(let key in data) {
let current = data[key];
let origin: string = comparison[key];
if(((this.actionType === ActionType.EDIT && !this.readonly && !current ) || current) && current !== origin) {
this.hasChanged = true;
if(((self.actionType === ActionType.EDIT && !self.readonly && !current ) || current) && current !== origin) {
self.hasChanged = true;
break;
} else {
this.hasChanged = false;
this.inlineAlert.close();
self.hasChanged = false;
self.inlineAlert.close();
}
}
});

View File

@ -10,7 +10,6 @@ import { TAG_DIRECTIVES } from './tag/index';
import { REPLICATION_DIRECTIVES } from './replication/index';
import { CREATE_EDIT_RULE_DIRECTIVES } from './create-edit-rule/index';
import { LIST_REPLICATION_RULE_DIRECTIVES } from './list-replication-rule/index';
import { LIST_REPLICATION_JOB_DIRECTIVES } from './list-replication-job/index';
import { CREATE_EDIT_ENDPOINT_DIRECTIVES } from './create-edit-endpoint/index';
@ -137,7 +136,6 @@ export function initConfig(translateService: TranslateService, config: IServiceC
INLINE_ALERT_DIRECTIVES,
REPLICATION_DIRECTIVES,
LIST_REPLICATION_RULE_DIRECTIVES,
LIST_REPLICATION_JOB_DIRECTIVES,
CREATE_EDIT_RULE_DIRECTIVES,
DATETIME_PICKER_DIRECTIVES
],
@ -153,7 +151,6 @@ export function initConfig(translateService: TranslateService, config: IServiceC
INLINE_ALERT_DIRECTIVES,
REPLICATION_DIRECTIVES,
LIST_REPLICATION_RULE_DIRECTIVES,
LIST_REPLICATION_JOB_DIRECTIVES,
CREATE_EDIT_RULE_DIRECTIVES,
DATETIME_PICKER_DIRECTIVES
],

View File

@ -253,6 +253,7 @@ export const EN_US_LANG: any = {
"CREATION_TIME": "Start Time",
"END_TIME": "End Time",
"LOGS": "Logs",
"OF": "of",
"ITEMS": "item(s)",
"TOGGLE_ENABLE_TITLE": "Enable Rule",
"CONFIRM_TOGGLE_ENABLE_POLICY": "After enabling the replication rule, all repositories under the project will be replicated to the destination registry. \nPlease confirm to continue.",

View File

@ -253,6 +253,7 @@ export const ZH_CN_LANG: any = {
"CREATION_TIME": "创建时间",
"END_TIME": "结束时间",
"LOGS": "日志",
"OF": "共计",
"ITEMS": "条记录",
"TOGGLE_ENABLE_TITLE": "启用规则",
"CONFIRM_TOGGLE_ENABLE_POLICY": "启用规则后,该项目下的所有镜像仓库将复制到目标实例。\n请确认继续。",

View File

@ -1,6 +0,0 @@
import { Type } from '@angular/core';
import { ListReplicationJobComponent } from './list-replication-job.component';
export const LIST_REPLICATION_JOB_DIRECTIVES: Type<any>[] = [
ListReplicationJobComponent
];

View File

@ -1,25 +0,0 @@
export const REPLICATION_JOB_TEMPLATE: string = `
<clr-datagrid (clrDgRefresh)="refresh($event)">
<clr-dg-column>{{'REPLICATION.NAME' | translate}}</clr-dg-column>
<clr-dg-column>{{'REPLICATION.STATUS' | translate}}</clr-dg-column>
<clr-dg-column>{{'REPLICATION.OPERATION' | translate}}</clr-dg-column>
<clr-dg-column>{{'REPLICATION.CREATION_TIME' | translate}}</clr-dg-column>
<clr-dg-column>{{'REPLICATION.END_TIME' | translate}}</clr-dg-column>
<clr-dg-column>{{'REPLICATION.LOGS' | translate}}</clr-dg-column>
<clr-dg-row *clrDgItems="let j of jobs" [clrDgItem]='j'>
<clr-dg-cell>{{j.repository}}</clr-dg-cell>
<clr-dg-cell>{{j.status}}</clr-dg-cell>
<clr-dg-cell>{{j.operation}}</clr-dg-cell>
<clr-dg-cell>{{j.creation_time}}</clr-dg-cell>
<clr-dg-cell>{{j.update_time}}</clr-dg-cell>
<clr-dg-cell>
<a href="/api/jobs/replication/{{j.id}}/log" target="_BLANK">
<clr-icon shape="clipboard"></clr-icon>
</a>
</clr-dg-cell>
</clr-dg-row>
<clr-dg-footer>
{{ jobs ? jobs.length : 0 }} {{'REPLICATION.ITEMS' | translate}}
<clr-dg-pagination [clrDgPageSize]="5"></clr-dg-pagination>
</clr-dg-footer>
</clr-datagrid>`;

View File

@ -1,94 +0,0 @@
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { NoopAnimationsModule } from "@angular/platform-browser/animations";
import { DebugElement } from '@angular/core';
import { SharedModule } from '../shared/shared.module';
import { ListReplicationJobComponent } from '../list-replication-job/list-replication-job.component';
import { ReplicationJob } from '../service/interface';
import { ErrorHandler } from '../error-handler/error-handler';
import { SERVICE_CONFIG, IServiceConfig } from '../service.config';
import { ReplicationService, ReplicationDefaultService } from '../service/replication.service';
describe('ListReplicationJobComponent (inline template)', ()=>{
let mockJobs: ReplicationJob[] = [
{
"id": 1,
"status": "stopped",
"repository": "library/busybox",
"policy_id": 1,
"operation": "transfer",
"tags": null
},
{
"id": 2,
"status": "stopped",
"repository": "library/busybox",
"policy_id": 1,
"operation": "transfer",
"tags": null
},
{
"id": 3,
"status": "stopped",
"repository": "library/busybox",
"policy_id": 2,
"operation": "transfer",
"tags": null
}
];
let fixture: ComponentFixture<ListReplicationJobComponent>;
let comp: ListReplicationJobComponent;
let replicationService: ReplicationService;
let spyJobs: jasmine.Spy;
let config: IServiceConfig = {
replicationJobEndpoint: '/api/policies/replication/testing'
};
beforeEach(async(()=>{
TestBed.configureTestingModule({
imports: [
SharedModule,
NoopAnimationsModule
],
declarations: [
ListReplicationJobComponent
],
providers: [
ErrorHandler,
{ provide: SERVICE_CONFIG, useValue: config },
{ provide: ReplicationService, useClass: ReplicationDefaultService }
]
});
}));
beforeEach(()=>{
fixture = TestBed.createComponent(ListReplicationJobComponent);
comp = fixture.componentInstance;
replicationService = fixture.debugElement.injector.get(ReplicationService);
spyJobs = spyOn(replicationService, 'getJobs').and.returnValues(Promise.resolve(mockJobs));
fixture.detectChanges();
});
it('Should load and render data', async(()=>{
fixture.detectChanges();
fixture.whenStable().then(()=>{
fixture.detectChanges();
let de: DebugElement = fixture.debugElement.query(By.css('datagrid-cell'));
expect(de).toBeTruthy();
fixture.detectChanges();
let el: HTMLElement = de.nativeElement;
expect(el.textContent.trim()).toEqual('library/busybox');
});
}));
});

View File

@ -1,46 +0,0 @@
// Copyright (c) 2017 VMware, Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
import { ReplicationJob } from '../service/interface';
import { State } from 'clarity-angular';
import { ErrorHandler } from '../error-handler/error-handler';
import { REPLICATION_JOB_TEMPLATE } from './list-replication-job.component.html';
@Component({
selector: 'list-replication-job',
template: REPLICATION_JOB_TEMPLATE,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ListReplicationJobComponent {
@Input() jobs: ReplicationJob[];
@Input() totalRecordCount: number;
@Input() totalPage: number;
@Output() paginate = new EventEmitter<State>();
constructor(
private errorHandler: ErrorHandler,
private ref: ChangeDetectorRef) {
let hnd = setInterval(()=>ref.markForCheck(), 100);
setTimeout(()=>clearInterval(hnd), 1000);
}
pageOffset: number = 1;
refresh(state: State) {
if(this.jobs) {
this.paginate.emit(state);
}
}
}

View File

@ -33,5 +33,8 @@ export const LIST_REPLICATION_RULE_TEMPLATE: string = `
{{ (p.enabled === 1 ? 'REPLICATION.ENABLED' : 'REPLICATION.DISABLED') | translate}}
</clr-dg-cell>
</clr-dg-row>
<clr-dg-footer>{{ (rules ? rules.length : 0) }} {{'REPLICATION.ITEMS' | translate}}</clr-dg-footer>
<clr-dg-footer>
{{pagination.firstItem + 1}} - {{pagination.lastItem +1 }} {{'REPLICATION.OF' | translate}} {{pagination.totalItems }} {{'REPLICATION.ITEMS' | translate}}
<clr-dg-pagination #pagination [clrDgPageSize]="5"></clr-dg-pagination>
</clr-dg-footer>
</clr-datagrid>`;

View File

@ -27,6 +27,8 @@ import { TranslateService } from '@ngx-translate/core';
import { ErrorHandler } from '../error-handler/error-handler';
import { toPromise } from '../utils';
import { State } from 'clarity-angular';
import { LIST_REPLICATION_RULE_TEMPLATE } from './list-replication-rule.component.html';
@Component({

View File

@ -46,6 +46,30 @@ export const REPLICATION_TEMPLATE: string = `
</div>
</div>
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
<list-replication-job [jobs]="jobs" [totalPage]="jobsTotalPage" [totalRecordCount]="jobsTotalRecordCount" (paginate)="fetchReplicationJobs($event)"></list-replication-job>
<clr-datagrid>
<clr-dg-column>{{'REPLICATION.NAME' | translate}}</clr-dg-column>
<clr-dg-column>{{'REPLICATION.STATUS' | translate}}</clr-dg-column>
<clr-dg-column>{{'REPLICATION.OPERATION' | translate}}</clr-dg-column>
<clr-dg-column>{{'REPLICATION.CREATION_TIME' | translate}}</clr-dg-column>
<clr-dg-column>{{'REPLICATION.END_TIME' | translate}}</clr-dg-column>
<clr-dg-column>{{'REPLICATION.LOGS' | translate}}</clr-dg-column>
<clr-dg-row *clrDgItems="let j of jobs" [clrDgItem]='j'>
<clr-dg-cell>{{j.repository}}</clr-dg-cell>
<clr-dg-cell>{{j.status}}</clr-dg-cell>
<clr-dg-cell>{{j.operation}}</clr-dg-cell>
<clr-dg-cell>{{j.creation_time}}</clr-dg-cell>
<clr-dg-cell>{{j.update_time}}</clr-dg-cell>
<clr-dg-cell>
<a href="/api/jobs/replication/{{j.id}}/log" target="_BLANK">
<clr-icon shape="clipboard"></clr-icon>
</a>
</clr-dg-cell>
</clr-dg-row>
<clr-dg-footer>
{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'REPLICATION.OF' | translate}}
{{pagination.totalItems}} {{'REPLICATION.ITEMS' | translate}}
<clr-dg-pagination #pagination [clrDgPageSize]="5"></clr-dg-pagination>
</clr-dg-footer>
</clr-datagrid>
</div>
</div>`;

View File

@ -7,7 +7,6 @@ import { SharedModule } from '../shared/shared.module';
import { ConfirmationDialogComponent } from '../confirmation-dialog/confirmation-dialog.component';
import { ReplicationComponent } from './replication.component';
import { ListReplicationRuleComponent } from '../list-replication-rule/list-replication-rule.component';
import { ListReplicationJobComponent } from '../list-replication-job/list-replication-job.component';
import { CreateEditRuleComponent } from '../create-edit-rule/create-edit-rule.component';
import { DatePickerComponent } from '../datetime-picker/datetime-picker.component';
import { DateValidatorDirective } from '../datetime-picker/date-validator.directive';
@ -71,6 +70,7 @@ describe('Replication Component (inline template)', ()=>{
"repository": "library/nginx",
"policy_id": 1,
"operation": "transfer",
"update_time": new Date("2017-05-23 12:20:33"),
"tags": null
},
{
@ -79,6 +79,7 @@ describe('Replication Component (inline template)', ()=>{
"repository": "library/mysql",
"policy_id": 1,
"operation": "transfer",
"update_time": new Date("2017-05-27 12:20:33"),
"tags": null
},
{
@ -87,6 +88,7 @@ describe('Replication Component (inline template)', ()=>{
"repository": "library/busybox",
"policy_id": 2,
"operation": "transfer",
"update_time": new Date("2017-04-23 12:20:33"),
"tags": null
}
];
@ -169,7 +171,6 @@ describe('Replication Component (inline template)', ()=>{
declarations: [
ReplicationComponent,
ListReplicationRuleComponent,
ListReplicationJobComponent,
CreateEditRuleComponent,
ConfirmationDialogComponent,
DatePickerComponent,
@ -283,4 +284,17 @@ describe('Replication Component (inline template)', ()=>{
expect(el.textContent.trim()).toEqual('library/mysql');
});
}));
it('Should filter replication jobs by date range', async(()=>{
fixture.detectChanges();
fixture.whenStable().then(()=>{
fixture.detectChanges();
comp.doJobSearchByStartTime('2017-05-01');
comp.doJobSearchByEndTime('2015-05-25');
let el: HTMLElement = deJobs.nativeElement;
fixture.detectChanges();
expect(el).toBeTruthy();
expect(el.textContent.trim()).toEqual('library/nginx');
});
}))
});

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component, OnInit, ViewChild, Input } from '@angular/core';
import { ResponseOptions } from '@angular/http';
import { ResponseOptions, RequestOptions } from '@angular/http';
import { NgModel } from '@angular/forms';
import { TranslateService } from '@ngx-translate/core';
@ -24,8 +24,6 @@ import { ReplicationService } from '../service/replication.service';
import { RequestQueryParams } from '../service/RequestQueryParams';
import { ReplicationRule, ReplicationJob, Endpoint } from '../service/interface';
import { State } from 'clarity-angular';
import { toPromise } from '../utils';
import { REPLICATION_TEMPLATE } from './replication.component.html';
@ -142,13 +140,8 @@ export class ReplicationComponent implements OnInit {
}
}
fetchReplicationJobs(state?: State) {
if(state && state.page) {
if(!state.page.to && state.page.to !== 0) {
return;
}
this.search.page = state.page.to + 1;
}
fetchReplicationJobs() {
let params: RequestQueryParams = new RequestQueryParams();
params.set('status', this.search.status);
params.set('repository', this.search.repoName);