mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-23 10:45:45 +01:00
* Change vul result bar texts * Support server-driven pagination for replication jobs
This commit is contained in:
parent
b4a81db15c
commit
baa863d026
@ -14,7 +14,7 @@ import { DatePickerComponent } from '../datetime-picker/datetime-picker.componen
|
|||||||
import { DateValidatorDirective } from '../datetime-picker/date-validator.directive';
|
import { DateValidatorDirective } from '../datetime-picker/date-validator.directive';
|
||||||
import { FilterComponent } from '../filter/filter.component';
|
import { FilterComponent } from '../filter/filter.component';
|
||||||
import { InlineAlertComponent } from '../inline-alert/inline-alert.component';
|
import { InlineAlertComponent } from '../inline-alert/inline-alert.component';
|
||||||
import { ReplicationRule, ReplicationJob, Endpoint } from '../service/interface';
|
import { ReplicationRule, ReplicationJob, Endpoint, ReplicationJobItem } from '../service/interface';
|
||||||
|
|
||||||
import { ErrorHandler } from '../error-handler/error-handler';
|
import { ErrorHandler } from '../error-handler/error-handler';
|
||||||
import { SERVICE_CONFIG, IServiceConfig } from '../service.config';
|
import { SERVICE_CONFIG, IServiceConfig } from '../service.config';
|
||||||
@ -71,7 +71,7 @@ describe('CreateEditRuleComponent (inline template)', ()=>{
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
let mockJobs: ReplicationJob[] = [
|
let mockJobs: ReplicationJobItem[] = [
|
||||||
{
|
{
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"status": "stopped",
|
"status": "stopped",
|
||||||
@ -98,6 +98,11 @@ describe('CreateEditRuleComponent (inline template)', ()=>{
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
let mockJob: ReplicationJob = {
|
||||||
|
metadata: {xTotalCount: 3},
|
||||||
|
data: mockJobs
|
||||||
|
};
|
||||||
|
|
||||||
let mockEndpoints: Endpoint[] = [
|
let mockEndpoints: Endpoint[] = [
|
||||||
{
|
{
|
||||||
"id": 1,
|
"id": 1,
|
||||||
@ -205,7 +210,7 @@ describe('CreateEditRuleComponent (inline template)', ()=>{
|
|||||||
|
|
||||||
spyRules = spyOn(replicationService, 'getReplicationRules').and.returnValues(Promise.resolve(mockRules));
|
spyRules = spyOn(replicationService, 'getReplicationRules').and.returnValues(Promise.resolve(mockRules));
|
||||||
spyOneRule = spyOn(replicationService, 'getReplicationRule').and.returnValue(Promise.resolve(mockRule));
|
spyOneRule = spyOn(replicationService, 'getReplicationRule').and.returnValue(Promise.resolve(mockRule));
|
||||||
spyJobs = spyOn(replicationService, 'getJobs').and.returnValues(Promise.resolve(mockJobs));
|
spyJobs = spyOn(replicationService, 'getJobs').and.returnValues(Promise.resolve(mockJob));
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ export const REPLICATION_TEMPLATE: string = `
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="withReplicationJob" class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
|
<div *ngIf="withReplicationJob" class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
|
||||||
<clr-datagrid [clrDgLoading]="loading">
|
<clr-datagrid [clrDgLoading]="jobsLoading" (clrDgRefresh)="clrLoadJobs($event)">
|
||||||
<clr-dg-column [clrDgField]="'repository'">{{'REPLICATION.NAME' | translate}}</clr-dg-column>
|
<clr-dg-column [clrDgField]="'repository'">{{'REPLICATION.NAME' | translate}}</clr-dg-column>
|
||||||
<clr-dg-column [clrDgField]="'status'">{{'REPLICATION.STATUS' | translate}}</clr-dg-column>
|
<clr-dg-column [clrDgField]="'status'">{{'REPLICATION.STATUS' | translate}}</clr-dg-column>
|
||||||
<clr-dg-column [clrDgField]="'operation'">{{'REPLICATION.OPERATION' | translate}}</clr-dg-column>
|
<clr-dg-column [clrDgField]="'operation'">{{'REPLICATION.OPERATION' | translate}}</clr-dg-column>
|
||||||
@ -54,7 +54,7 @@ export const REPLICATION_TEMPLATE: string = `
|
|||||||
<clr-dg-column [clrDgSortBy]="updateTimeComparator">{{'REPLICATION.UPDATE_TIME' | translate}}</clr-dg-column>
|
<clr-dg-column [clrDgSortBy]="updateTimeComparator">{{'REPLICATION.UPDATE_TIME' | translate}}</clr-dg-column>
|
||||||
<clr-dg-column>{{'REPLICATION.LOGS' | translate}}</clr-dg-column>
|
<clr-dg-column>{{'REPLICATION.LOGS' | translate}}</clr-dg-column>
|
||||||
<clr-dg-placeholder>{{'REPLICATION.JOB_PLACEHOLDER' | translate }}</clr-dg-placeholder>
|
<clr-dg-placeholder>{{'REPLICATION.JOB_PLACEHOLDER' | translate }}</clr-dg-placeholder>
|
||||||
<clr-dg-row *clrDgItems="let j of jobs" [clrDgItem]='j'>
|
<clr-dg-row *ngFor="let j of jobs">
|
||||||
<clr-dg-cell>{{j.repository}}</clr-dg-cell>
|
<clr-dg-cell>{{j.repository}}</clr-dg-cell>
|
||||||
<clr-dg-cell>{{j.status}}</clr-dg-cell>
|
<clr-dg-cell>{{j.status}}</clr-dg-cell>
|
||||||
<clr-dg-cell>{{j.operation}}</clr-dg-cell>
|
<clr-dg-cell>{{j.operation}}</clr-dg-cell>
|
||||||
@ -66,13 +66,12 @@ export const REPLICATION_TEMPLATE: string = `
|
|||||||
<a href="javascript:void(0);" (click)="viewLog(j.id)">
|
<a href="javascript:void(0);" (click)="viewLog(j.id)">
|
||||||
<clr-icon shape="clipboard"></clr-icon>
|
<clr-icon shape="clipboard"></clr-icon>
|
||||||
</a></ng-template>
|
</a></ng-template>
|
||||||
|
|
||||||
</clr-dg-cell>
|
</clr-dg-cell>
|
||||||
</clr-dg-row>
|
</clr-dg-row>
|
||||||
<clr-dg-footer>
|
<clr-dg-footer>
|
||||||
<span *ngIf="pagination.totalItems">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'REPLICATION.OF' | translate}}</span>
|
<span *ngIf="showPaginationIndex">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'REPLICATION.OF' | translate}}</span>
|
||||||
{{pagination.totalItems}} {{'REPLICATION.ITEMS' | translate}}
|
{{pagination.totalItems}} {{'REPLICATION.ITEMS' | translate}}
|
||||||
<clr-dg-pagination #pagination [clrDgPageSize]="5"></clr-dg-pagination>
|
<clr-dg-pagination #pagination [(clrDgPage)]="currentPage" [clrDgPageSize]="pageSize" [clrDgTotalItems]="totalCount"></clr-dg-pagination>
|
||||||
</clr-dg-footer>
|
</clr-dg-footer>
|
||||||
</clr-datagrid>
|
</clr-datagrid>
|
||||||
</div>
|
</div>
|
||||||
|
@ -19,7 +19,7 @@ import { SERVICE_CONFIG, IServiceConfig } from '../service.config';
|
|||||||
import { ReplicationService, ReplicationDefaultService } from '../service/replication.service';
|
import { ReplicationService, ReplicationDefaultService } from '../service/replication.service';
|
||||||
import { EndpointService, EndpointDefaultService } from '../service/endpoint.service';
|
import { EndpointService, EndpointDefaultService } from '../service/endpoint.service';
|
||||||
import { JobLogViewerComponent } from '../job-log-viewer/job-log-viewer.component';
|
import { JobLogViewerComponent } from '../job-log-viewer/job-log-viewer.component';
|
||||||
import { JobLogService, JobLogDefaultService } from '../service/index';
|
import { JobLogService, JobLogDefaultService, ReplicationJobItem } from '../service/index';
|
||||||
|
|
||||||
describe('Replication Component (inline template)', ()=>{
|
describe('Replication Component (inline template)', ()=>{
|
||||||
|
|
||||||
@ -65,7 +65,7 @@ describe('Replication Component (inline template)', ()=>{
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
let mockJobs: ReplicationJob[] = [
|
let mockJobs: ReplicationJobItem[] = [
|
||||||
{
|
{
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"status": "error",
|
"status": "error",
|
||||||
@ -95,6 +95,11 @@ describe('Replication Component (inline template)', ()=>{
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
let mockJob: ReplicationJob = {
|
||||||
|
metadata: {xTotalCount: 3},
|
||||||
|
data: mockJobs
|
||||||
|
};
|
||||||
|
|
||||||
let mockEndpoints: Endpoint[] = [
|
let mockEndpoints: Endpoint[] = [
|
||||||
{
|
{
|
||||||
"id": 1,
|
"id": 1,
|
||||||
@ -200,7 +205,7 @@ describe('Replication Component (inline template)', ()=>{
|
|||||||
replicationService = fixture.debugElement.injector.get(ReplicationService);
|
replicationService = fixture.debugElement.injector.get(ReplicationService);
|
||||||
|
|
||||||
spyRules = spyOn(replicationService, 'getReplicationRules').and.returnValues(Promise.resolve(mockRules));
|
spyRules = spyOn(replicationService, 'getReplicationRules').and.returnValues(Promise.resolve(mockRules));
|
||||||
spyJobs = spyOn(replicationService, 'getJobs').and.returnValues(Promise.resolve(mockJobs));
|
spyJobs = spyOn(replicationService, 'getJobs').and.returnValues(Promise.resolve(mockJob));
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
fixture.whenStable().then(()=>{
|
fixture.whenStable().then(()=>{
|
||||||
|
@ -23,9 +23,16 @@ import { ErrorHandler } from '../error-handler/error-handler';
|
|||||||
|
|
||||||
import { ReplicationService } from '../service/replication.service';
|
import { ReplicationService } from '../service/replication.service';
|
||||||
import { RequestQueryParams } from '../service/RequestQueryParams';
|
import { RequestQueryParams } from '../service/RequestQueryParams';
|
||||||
import { ReplicationRule, ReplicationJob, Endpoint } from '../service/interface';
|
import { ReplicationRule, ReplicationJob, Endpoint, ReplicationJobItem } from '../service/interface';
|
||||||
|
|
||||||
import { toPromise, CustomComparator } from '../utils';
|
import {
|
||||||
|
toPromise,
|
||||||
|
CustomComparator,
|
||||||
|
DEFAULT_PAGE_SIZE,
|
||||||
|
doFiltering,
|
||||||
|
doSorting,
|
||||||
|
calculatePage
|
||||||
|
} from '../utils';
|
||||||
|
|
||||||
import { Comparator } from 'clarity-angular';
|
import { Comparator } from 'clarity-angular';
|
||||||
|
|
||||||
@ -33,6 +40,7 @@ import { REPLICATION_TEMPLATE } from './replication.component.html';
|
|||||||
import { REPLICATION_STYLE } from './replication.component.css';
|
import { REPLICATION_STYLE } from './replication.component.css';
|
||||||
|
|
||||||
import { JobLogViewerComponent } from '../job-log-viewer/index';
|
import { JobLogViewerComponent } from '../job-log-viewer/index';
|
||||||
|
import { State } from "clarity-angular";
|
||||||
|
|
||||||
const ruleStatus: { [key: string]: any } = [
|
const ruleStatus: { [key: string]: any } = [
|
||||||
{ 'key': 'all', 'description': 'REPLICATION.ALL_STATUS' },
|
{ 'key': 'all', 'description': 'REPLICATION.ALL_STATUS' },
|
||||||
@ -63,7 +71,7 @@ export class SearchOption {
|
|||||||
endTime: string = '';
|
endTime: string = '';
|
||||||
endTimestamp: string = '';
|
endTimestamp: string = '';
|
||||||
page: number = 1;
|
page: number = 1;
|
||||||
pageSize: number = 5;
|
pageSize: number = DEFAULT_PAGE_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -93,10 +101,7 @@ export class ReplicationComponent implements OnInit {
|
|||||||
rules: ReplicationRule[];
|
rules: ReplicationRule[];
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
|
|
||||||
jobs: ReplicationJob[];
|
jobs: ReplicationJobItem[];
|
||||||
|
|
||||||
jobsTotalRecordCount: number;
|
|
||||||
jobsTotalPage: number;
|
|
||||||
|
|
||||||
toggleJobSearchOption = optionalSearch;
|
toggleJobSearchOption = optionalSearch;
|
||||||
currentJobSearchOption: number;
|
currentJobSearchOption: number;
|
||||||
@ -113,6 +118,13 @@ export class ReplicationComponent implements OnInit {
|
|||||||
creationTimeComparator: Comparator<ReplicationJob> = new CustomComparator<ReplicationJob>('creation_time', 'date');
|
creationTimeComparator: Comparator<ReplicationJob> = new CustomComparator<ReplicationJob>('creation_time', 'date');
|
||||||
updateTimeComparator: Comparator<ReplicationJob> = new CustomComparator<ReplicationJob>('update_time', 'date');
|
updateTimeComparator: Comparator<ReplicationJob> = new CustomComparator<ReplicationJob>('update_time', 'date');
|
||||||
|
|
||||||
|
//Server driven pagination
|
||||||
|
currentPage: number = 1;
|
||||||
|
totalCount: number = 0;
|
||||||
|
pageSize: number = DEFAULT_PAGE_SIZE;
|
||||||
|
currentState: State;
|
||||||
|
jobsLoading: boolean = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private errorHandler: ErrorHandler,
|
private errorHandler: ErrorHandler,
|
||||||
private replicationService: ReplicationService,
|
private replicationService: ReplicationService,
|
||||||
@ -123,6 +135,10 @@ export class ReplicationComponent implements OnInit {
|
|||||||
return !this.readonly && this.projectId ? true : false;
|
return !this.readonly && this.projectId ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get showPaginationIndex(): boolean {
|
||||||
|
return this.totalCount > 0;
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.currentRuleStatus = this.ruleStatus[0];
|
this.currentRuleStatus = this.ruleStatus[0];
|
||||||
this.currentJobStatus = this.jobStatus[0];
|
this.currentJobStatus = this.jobStatus[0];
|
||||||
@ -143,32 +159,78 @@ export class ReplicationComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchReplicationJobs() {
|
//Server driven data loading
|
||||||
|
clrLoadJobs(state: State): void {
|
||||||
|
if (!state || !state.page || !this.search.ruleId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.currentState = state;
|
||||||
|
|
||||||
|
let pageNumber: number = calculatePage(state);
|
||||||
|
if (pageNumber <= 0) { pageNumber = 1; }
|
||||||
|
|
||||||
let params: RequestQueryParams = new RequestQueryParams();
|
let params: RequestQueryParams = new RequestQueryParams();
|
||||||
params.set('status', this.search.status);
|
//Pagination
|
||||||
params.set('repository', this.search.repoName);
|
params.set("page", '' + pageNumber);
|
||||||
params.set('start_time', this.search.startTimestamp);
|
params.set("page_size", '' + this.pageSize);
|
||||||
params.set('end_time', this.search.endTimestamp);
|
//Search by status
|
||||||
|
if (this.search.status.trim()) {
|
||||||
|
params.set('status', this.search.status);
|
||||||
|
}
|
||||||
|
//Search by repository
|
||||||
|
if (this.search.repoName.trim()) {
|
||||||
|
params.set('repository', this.search.repoName);
|
||||||
|
}
|
||||||
|
//Search by timestamps
|
||||||
|
if (this.search.startTimestamp.trim()) {
|
||||||
|
params.set('start_time', this.search.startTimestamp);
|
||||||
|
}
|
||||||
|
if (this.search.endTimestamp.trim()) {
|
||||||
|
params.set('end_time', this.search.endTimestamp);
|
||||||
|
}
|
||||||
|
|
||||||
toPromise<ReplicationJob[]>(this.replicationService
|
this.jobsLoading = true;
|
||||||
|
toPromise<ReplicationJob>(this.replicationService
|
||||||
.getJobs(this.search.ruleId, params))
|
.getJobs(this.search.ruleId, params))
|
||||||
.then(
|
.then(
|
||||||
response => {
|
response => {
|
||||||
this.jobs = response;
|
this.totalCount = response.metadata.xTotalCount;
|
||||||
|
this.jobs = response.data;
|
||||||
|
|
||||||
|
//Do filtering and sorting
|
||||||
|
this.jobs = doFiltering<ReplicationJobItem>(this.jobs, state);
|
||||||
|
this.jobs = doSorting<ReplicationJobItem>(this.jobs, state);
|
||||||
|
|
||||||
|
this.jobsLoading = false;
|
||||||
|
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
|
this.jobsLoading = false;
|
||||||
this.errorHandler.error(error);
|
this.errorHandler.error(error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loadFirstPage(): void {
|
||||||
|
let st: State = this.currentState;
|
||||||
|
if (!st) {
|
||||||
|
st = {
|
||||||
|
page: {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
st.page.size = this.pageSize;
|
||||||
|
st.page.from = 0;
|
||||||
|
st.page.to = this.pageSize - 1;
|
||||||
|
|
||||||
|
this.clrLoadJobs(st);
|
||||||
|
}
|
||||||
|
|
||||||
selectOneRule(rule: ReplicationRule) {
|
selectOneRule(rule: ReplicationRule) {
|
||||||
if (rule) {
|
if (rule && rule.id) {
|
||||||
this.search.ruleId = rule.id || '';
|
this.search.ruleId = rule.id || '';
|
||||||
this.search.repoName = '';
|
this.search.repoName = '';
|
||||||
this.search.status = '';
|
this.search.status = '';
|
||||||
this.currentJobSearchOption = 0;
|
this.currentJobSearchOption = 0;
|
||||||
this.currentJobStatus = { 'key': 'all', 'description': 'REPLICATION.ALL' };
|
this.currentJobStatus = { 'key': 'all', 'description': 'REPLICATION.ALL' };
|
||||||
this.fetchReplicationJobs();
|
this.loadFirstPage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,7 +267,7 @@ export class ReplicationComponent implements OnInit {
|
|||||||
|
|
||||||
doSearchJobs(repoName: string) {
|
doSearchJobs(repoName: string) {
|
||||||
this.search.repoName = repoName;
|
this.search.repoName = repoName;
|
||||||
this.fetchReplicationJobs();
|
this.loadFirstPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
reloadRules(isReady: boolean) {
|
reloadRules(isReady: boolean) {
|
||||||
@ -220,7 +282,21 @@ export class ReplicationComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
refreshJobs() {
|
refreshJobs() {
|
||||||
this.fetchReplicationJobs();
|
this.search.repoName = "";
|
||||||
|
this.search.startTimestamp = "";
|
||||||
|
this.search.endTimestamp = "";
|
||||||
|
this.search.status = "";
|
||||||
|
|
||||||
|
this.currentPage = 1;
|
||||||
|
|
||||||
|
let st: State = {
|
||||||
|
page: {
|
||||||
|
from: 0,
|
||||||
|
to: this.pageSize - 1,
|
||||||
|
size: this.pageSize
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.clrLoadJobs(st);
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleSearchJobOptionalName(option: number) {
|
toggleSearchJobOptionalName(option: number) {
|
||||||
@ -229,12 +305,12 @@ export class ReplicationComponent implements OnInit {
|
|||||||
|
|
||||||
doJobSearchByStartTime(fromTimestamp: string) {
|
doJobSearchByStartTime(fromTimestamp: string) {
|
||||||
this.search.startTimestamp = fromTimestamp;
|
this.search.startTimestamp = fromTimestamp;
|
||||||
this.fetchReplicationJobs();
|
this.loadFirstPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
doJobSearchByEndTime(toTimestamp: string) {
|
doJobSearchByEndTime(toTimestamp: string) {
|
||||||
this.search.endTimestamp = toTimestamp;
|
this.search.endTimestamp = toTimestamp;
|
||||||
this.fetchReplicationJobs();
|
this.loadFirstPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
viewLog(jobId: number | string): void {
|
viewLog(jobId: number | string): void {
|
||||||
|
@ -100,7 +100,19 @@ export interface ReplicationRule extends Base {
|
|||||||
* @export
|
* @export
|
||||||
* @interface ReplicationJob
|
* @interface ReplicationJob
|
||||||
*/
|
*/
|
||||||
export interface ReplicationJob extends Base {
|
export interface ReplicationJob {
|
||||||
|
metadata?: Metadata;
|
||||||
|
data: ReplicationJobItem[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for replication job item.
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @interface ReplicationJob
|
||||||
|
*/
|
||||||
|
export interface ReplicationJobItem extends Base {
|
||||||
|
[key: string]: any | any[]
|
||||||
status: string;
|
status: string;
|
||||||
repository: string;
|
repository: string;
|
||||||
policy_id: number;
|
policy_id: number;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
import { RequestQueryParams } from './RequestQueryParams';
|
import { RequestQueryParams } from './RequestQueryParams';
|
||||||
import { ReplicationJob, ReplicationRule } from './interface';
|
import { ReplicationJob, ReplicationRule, ReplicationJobItem } from './interface';
|
||||||
import { Injectable, Inject } from "@angular/core";
|
import { Injectable, Inject } from "@angular/core";
|
||||||
import 'rxjs/add/observable/of';
|
import 'rxjs/add/observable/of';
|
||||||
import { Http, RequestOptions } from '@angular/http';
|
import { Http, RequestOptions } from '@angular/http';
|
||||||
@ -109,11 +109,11 @@ export abstract class ReplicationService {
|
|||||||
* @abstract
|
* @abstract
|
||||||
* @param {(number | string)} ruleId
|
* @param {(number | string)} ruleId
|
||||||
* @param {RequestQueryParams} [queryParams]
|
* @param {RequestQueryParams} [queryParams]
|
||||||
* @returns {(Observable<ReplicationJob> | Promise<ReplicationJob[]> | ReplicationJob)}
|
* @returns {(Observable<ReplicationJob> | Promise<ReplicationJob> | ReplicationJob)}
|
||||||
*
|
*
|
||||||
* @memberOf ReplicationService
|
* @memberOf ReplicationService
|
||||||
*/
|
*/
|
||||||
abstract getJobs(ruleId: number | string, queryParams?: RequestQueryParams): Observable<ReplicationJob[]> | Promise<ReplicationJob[]> | ReplicationJob[];
|
abstract getJobs(ruleId: number | string, queryParams?: RequestQueryParams): Observable<ReplicationJob> | Promise<ReplicationJob> | ReplicationJob;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the log of the specified job.
|
* Get the log of the specified job.
|
||||||
@ -238,7 +238,7 @@ export class ReplicationDefaultService extends ReplicationService {
|
|||||||
.catch(error => Promise.reject(error));
|
.catch(error => Promise.reject(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
public getJobs(ruleId: number | string, queryParams?: RequestQueryParams): Observable<ReplicationJob[]> | Promise<ReplicationJob[]> | ReplicationJob[] {
|
public getJobs(ruleId: number | string, queryParams?: RequestQueryParams): Observable<ReplicationJob> | Promise<ReplicationJob> | ReplicationJob {
|
||||||
if (!ruleId || ruleId <= 0) {
|
if (!ruleId || ruleId <= 0) {
|
||||||
return Promise.reject('Bad argument');
|
return Promise.reject('Bad argument');
|
||||||
}
|
}
|
||||||
@ -249,7 +249,29 @@ export class ReplicationDefaultService extends ReplicationService {
|
|||||||
|
|
||||||
queryParams.set('policy_id', '' + ruleId);
|
queryParams.set('policy_id', '' + ruleId);
|
||||||
return this.http.get(this._jobBaseUrl, buildHttpRequestOptions(queryParams)).toPromise()
|
return this.http.get(this._jobBaseUrl, buildHttpRequestOptions(queryParams)).toPromise()
|
||||||
.then(response => response.json() as ReplicationJob[])
|
.then(response => {
|
||||||
|
let result: ReplicationJob = {
|
||||||
|
metadata: {
|
||||||
|
xTotalCount: 0
|
||||||
|
},
|
||||||
|
data: []
|
||||||
|
};
|
||||||
|
|
||||||
|
if (response && response.headers) {
|
||||||
|
let xHeader: string = response.headers.get("X-Total-Count");
|
||||||
|
if (xHeader) {
|
||||||
|
result.metadata.xTotalCount = parseInt(xHeader, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.data = response.json() as ReplicationJobItem[];
|
||||||
|
if (result.metadata.xTotalCount === 0) {
|
||||||
|
if (result.data && result.data.length > 0) {
|
||||||
|
result.metadata.xTotalCount = result.data.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
})
|
||||||
.catch(error => Promise.reject(error));
|
.catch(error => Promise.reject(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,7 +282,7 @@ export class ReplicationDefaultService extends ReplicationService {
|
|||||||
|
|
||||||
let logUrl: string = `${this._jobBaseUrl}/${jobId}/log`;
|
let logUrl: string = `${this._jobBaseUrl}/${jobId}/log`;
|
||||||
return this.http.get(logUrl).toPromise()
|
return this.http.get(logUrl).toPromise()
|
||||||
.then(response => response.text())
|
.then(response => response.text())
|
||||||
.catch(error => Promise.reject(error));
|
.catch(error => Promise.reject(error));
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -92,6 +92,12 @@ export class RepositoryDefaultService extends RepositoryService {
|
|||||||
|
|
||||||
result.data = response.json() as RepositoryItem[];
|
result.data = response.json() as RepositoryItem[];
|
||||||
|
|
||||||
|
if (result.metadata.xTotalCount === 0) {
|
||||||
|
if (result.data && result.data.length > 0) {
|
||||||
|
result.metadata.xTotalCount = result.data.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
})
|
})
|
||||||
.catch(error => Promise.reject(error));
|
.catch(error => Promise.reject(error));
|
||||||
|
@ -67,18 +67,19 @@ export class ResultTipComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
this.translate.get(this.packageText(this.totalPackages)).subscribe((p1: string) => {
|
this.translate.get(this.packageText(this.totalPackages)).subscribe((p1: string) => {
|
||||||
this.translate.get(this.packageText(this.packagesWithVul)).subscribe((p2: string) => {
|
this.translate.get(this.unitText(this.packagesWithVul)).subscribe((vul: string) => {
|
||||||
this.translate.get(this.unitText(this.packagesWithVul)).subscribe((vul: string) => {
|
let messageKey: string = "VULNERABILITY.CHART.TOOLTIPS_TITLE";
|
||||||
this.translate.get('VULNERABILITY.CHART.TOOLTIPS_TITLE',
|
if (this.packagesWithVul > 1) {
|
||||||
{
|
messageKey = "VULNERABILITY.CHART.TOOLTIPS_TITLE_SINGULAR";
|
||||||
totalVulnerability: this.packagesWithVul,
|
}
|
||||||
totalPackages: this.totalPackages,
|
this.translate.get(messageKey,
|
||||||
package: p1,
|
{
|
||||||
packageExt: p2,
|
totalVulnerability: this.packagesWithVul,
|
||||||
vulnerability: vul
|
totalPackages: this.totalPackages,
|
||||||
})
|
package: p1,
|
||||||
.subscribe((res: string) => this._tipTitle = res);
|
vulnerability: vul
|
||||||
});
|
})
|
||||||
|
.subscribe((res: string) => this._tipTitle = res);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
"clarity-icons": "^0.9.8",
|
"clarity-icons": "^0.9.8",
|
||||||
"clarity-ui": "^0.9.8",
|
"clarity-ui": "^0.9.8",
|
||||||
"core-js": "^2.4.1",
|
"core-js": "^2.4.1",
|
||||||
"harbor-ui": "0.3.66",
|
"harbor-ui": "0.3.91",
|
||||||
"intl": "^1.2.5",
|
"intl": "^1.2.5",
|
||||||
"mutationobserver-shim": "^0.3.2",
|
"mutationobserver-shim": "^0.3.2",
|
||||||
"ngx-cookie": "^1.0.0",
|
"ngx-cookie": "^1.0.0",
|
||||||
|
@ -56,9 +56,8 @@
|
|||||||
<clr-dg-cell>{{l.op_time | date: 'short'}}</clr-dg-cell>
|
<clr-dg-cell>{{l.op_time | date: 'short'}}</clr-dg-cell>
|
||||||
</clr-dg-row>
|
</clr-dg-row>
|
||||||
<clr-dg-footer>
|
<clr-dg-footer>
|
||||||
<span *ngIf="pagination.totalItems">{{pagination.firstItem + 1}} - {{pagination.lastItem +1 }} {{'AUDIT_LOG.OF' | translate}} </span>
|
<span *ngIf="showPaginationIndex">{{pagination.firstItem + 1}} - {{pagination.lastItem +1 }} {{'AUDIT_LOG.OF' | translate}} </span> {{pagination.totalItems }} {{'AUDIT_LOG.ITEMS' | translate}}
|
||||||
{{pagination.totalItems }} {{'AUDIT_LOG.ITEMS' | translate}}
|
<clr-dg-pagination #pagination [clrDgPageSize]="15" [(clrDgPage)]="currentPage" [clrDgTotalItems]="totalRecordCount"></clr-dg-pagination>
|
||||||
<clr-dg-pagination #pagination [clrDgPageSize]="15" [(clrDgPage)]="currentPage" [clrDgTotalItems]="totalRecordCount"></clr-dg-pagination>
|
|
||||||
<!--{{totalRecordCount}} {{'AUDIT_LOG.ITEMS' | translate}}
|
<!--{{totalRecordCount}} {{'AUDIT_LOG.ITEMS' | translate}}
|
||||||
<clr-dg-pagination [clrDgPageSize]="pageOffset" [clrDgTotalItems]="totalPage"></clr-dg-pagination>-->
|
<clr-dg-pagination [clrDgPageSize]="pageOffset" [clrDgTotalItems]="totalPage"></clr-dg-pagination>-->
|
||||||
</clr-dg-footer>
|
</clr-dg-footer>
|
||||||
|
@ -25,7 +25,7 @@ import { AlertType } from '../shared/shared.const';
|
|||||||
|
|
||||||
import { State } from 'clarity-angular';
|
import { State } from 'clarity-angular';
|
||||||
|
|
||||||
const optionalSearch: {} = {0: 'AUDIT_LOG.ADVANCED', 1: 'AUDIT_LOG.SIMPLE'};
|
const optionalSearch: {} = { 0: 'AUDIT_LOG.ADVANCED', 1: 'AUDIT_LOG.SIMPLE' };
|
||||||
|
|
||||||
class FilterOption {
|
class FilterOption {
|
||||||
key: string;
|
key: string;
|
||||||
@ -46,7 +46,7 @@ class FilterOption {
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'audit-log',
|
selector: 'audit-log',
|
||||||
templateUrl: './audit-log.component.html',
|
templateUrl: './audit-log.component.html',
|
||||||
styleUrls: [ './audit-log.component.css' ]
|
styleUrls: ['./audit-log.component.css']
|
||||||
})
|
})
|
||||||
export class AuditLogComponent implements OnInit {
|
export class AuditLogComponent implements OnInit {
|
||||||
|
|
||||||
@ -64,11 +64,11 @@ export class AuditLogComponent implements OnInit {
|
|||||||
new FilterOption('create', 'AUDIT_LOG.CREATE', true),
|
new FilterOption('create', 'AUDIT_LOG.CREATE', true),
|
||||||
new FilterOption('delete', 'AUDIT_LOG.DELETE', true),
|
new FilterOption('delete', 'AUDIT_LOG.DELETE', true),
|
||||||
new FilterOption('others', 'AUDIT_LOG.OTHERS', true)
|
new FilterOption('others', 'AUDIT_LOG.OTHERS', true)
|
||||||
];
|
];
|
||||||
|
|
||||||
pageOffset: number = 1;
|
pageOffset: number = 1;
|
||||||
pageSize: number = 15;
|
pageSize: number = 15;
|
||||||
totalRecordCount: number;
|
totalRecordCount: number = 0;
|
||||||
currentPage: number;
|
currentPage: number;
|
||||||
totalPage: number;
|
totalPage: number;
|
||||||
|
|
||||||
@ -83,9 +83,13 @@ export class AuditLogComponent implements OnInit {
|
|||||||
return this.toTimeInput.errors && this.toTimeInput.errors.dateValidator && (this.toTimeInput.dirty || this.toTimeInput.touched);
|
return this.toTimeInput.errors && this.toTimeInput.errors.dateValidator && (this.toTimeInput.dirty || this.toTimeInput.touched);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get showPaginationIndex(): boolean {
|
||||||
|
return this.totalRecordCount > 0;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(private route: ActivatedRoute, private router: Router, private auditLogService: AuditLogService, private messageHandlerService: MessageHandlerService) {
|
constructor(private route: ActivatedRoute, private router: Router, private auditLogService: AuditLogService, private messageHandlerService: MessageHandlerService) {
|
||||||
//Get current user from registered resolver.
|
//Get current user from registered resolver.
|
||||||
this.route.data.subscribe(data=>this.currentUser = <SessionUser>data['auditLogResolver']);
|
this.route.data.subscribe(data => this.currentUser = <SessionUser>data['auditLogResolver']);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
@ -96,22 +100,22 @@ export class AuditLogComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
retrieve(state?: State): void {
|
retrieve(state?: State): void {
|
||||||
if(state) {
|
if (state) {
|
||||||
this.queryParam.page = Math.ceil((state.page.to + 1) / this.pageSize);
|
this.queryParam.page = Math.ceil((state.page.to + 1) / this.pageSize);
|
||||||
this.currentPage = this.queryParam.page;
|
this.currentPage = this.queryParam.page;
|
||||||
}
|
}
|
||||||
this.auditLogService
|
this.auditLogService
|
||||||
.listAuditLogs(this.queryParam)
|
.listAuditLogs(this.queryParam)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
response=>{
|
response => {
|
||||||
this.totalRecordCount =parseInt(response.headers.get('x-total-count'));
|
this.totalRecordCount = parseInt(response.headers.get('x-total-count'));
|
||||||
this.auditLogs = response.json();
|
this.auditLogs = response.json();
|
||||||
},
|
},
|
||||||
error=>{
|
error => {
|
||||||
this.router.navigate(['/harbor', 'projects']);
|
this.router.navigate(['/harbor', 'projects']);
|
||||||
this.messageHandlerService.handleError(error);
|
this.messageHandlerService.handleError(error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
doSearchAuditLogs(searchUsername: string): void {
|
doSearchAuditLogs(searchUsername: string): void {
|
||||||
@ -120,16 +124,16 @@ export class AuditLogComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
convertDate(strDate: string): string {
|
convertDate(strDate: string): string {
|
||||||
if(/^(0[1-9]|[12][0-9]|3[01])[- /.](0[1-9]|1[012])[- /.](19|20)\d\d$/.test(strDate)) {
|
if (/^(0[1-9]|[12][0-9]|3[01])[- /.](0[1-9]|1[012])[- /.](19|20)\d\d$/.test(strDate)) {
|
||||||
let parts = strDate.split(/[-\/]/);
|
let parts = strDate.split(/[-\/]/);
|
||||||
strDate = parts[2] /*Year*/ + '-' +parts[1] /*Month*/ + '-' + parts[0] /*Date*/;
|
strDate = parts[2] /*Year*/ + '-' + parts[1] /*Month*/ + '-' + parts[0] /*Date*/;
|
||||||
}
|
}
|
||||||
return strDate;
|
return strDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
doSearchByStartTime(strDate: string): void {
|
doSearchByStartTime(strDate: string): void {
|
||||||
this.queryParam.begin_timestamp = 0;
|
this.queryParam.begin_timestamp = 0;
|
||||||
if(this.fromTimeInput.valid && strDate){
|
if (this.fromTimeInput.valid && strDate) {
|
||||||
strDate = this.convertDate(strDate);
|
strDate = this.convertDate(strDate);
|
||||||
this.queryParam.begin_timestamp = new Date(strDate).getTime() / 1000;
|
this.queryParam.begin_timestamp = new Date(strDate).getTime() / 1000;
|
||||||
}
|
}
|
||||||
@ -138,7 +142,7 @@ export class AuditLogComponent implements OnInit {
|
|||||||
|
|
||||||
doSearchByEndTime(strDate: string): void {
|
doSearchByEndTime(strDate: string): void {
|
||||||
this.queryParam.end_timestamp = 0;
|
this.queryParam.end_timestamp = 0;
|
||||||
if(this.toTimeInput.valid && strDate) {
|
if (this.toTimeInput.valid && strDate) {
|
||||||
strDate = this.convertDate(strDate);
|
strDate = this.convertDate(strDate);
|
||||||
let oneDayOffset = 3600 * 24;
|
let oneDayOffset = 3600 * 24;
|
||||||
this.queryParam.end_timestamp = new Date(strDate).getTime() / 1000 + oneDayOffset;
|
this.queryParam.end_timestamp = new Date(strDate).getTime() / 1000 + oneDayOffset;
|
||||||
@ -149,15 +153,15 @@ export class AuditLogComponent implements OnInit {
|
|||||||
doSearchByOptions() {
|
doSearchByOptions() {
|
||||||
let selectAll = true;
|
let selectAll = true;
|
||||||
let operationFilter: string[] = [];
|
let operationFilter: string[] = [];
|
||||||
for(var i in this.filterOptions) {
|
for (var i in this.filterOptions) {
|
||||||
let filterOption = this.filterOptions[i];
|
let filterOption = this.filterOptions[i];
|
||||||
if(filterOption.checked) {
|
if (filterOption.checked) {
|
||||||
operationFilter.push('operation=' + this.filterOptions[i].key);
|
operationFilter.push('operation=' + this.filterOptions[i].key);
|
||||||
}else{
|
} else {
|
||||||
selectAll = false;
|
selectAll = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(selectAll) {
|
if (selectAll) {
|
||||||
operationFilter = [];
|
operationFilter = [];
|
||||||
}
|
}
|
||||||
this.queryParam.keywords = operationFilter.join('&');
|
this.queryParam.keywords = operationFilter.join('&');
|
||||||
@ -169,21 +173,21 @@ export class AuditLogComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
toggleFilterOption(option: string): void {
|
toggleFilterOption(option: string): void {
|
||||||
let selectedOption = this.filterOptions.find(value =>(value.key === option));
|
let selectedOption = this.filterOptions.find(value => (value.key === option));
|
||||||
selectedOption.checked = !selectedOption.checked;
|
selectedOption.checked = !selectedOption.checked;
|
||||||
if(selectedOption.key === 'all') {
|
if (selectedOption.key === 'all') {
|
||||||
this.filterOptions.filter(value=> value.key !== selectedOption.key).forEach(value => value.checked = selectedOption.checked);
|
this.filterOptions.filter(value => value.key !== selectedOption.key).forEach(value => value.checked = selectedOption.checked);
|
||||||
} else {
|
} else {
|
||||||
if(!selectedOption.checked) {
|
if (!selectedOption.checked) {
|
||||||
this.filterOptions.find(value=>value.key === 'all').checked = false;
|
this.filterOptions.find(value => value.key === 'all').checked = false;
|
||||||
}
|
}
|
||||||
let selectAll = true;
|
let selectAll = true;
|
||||||
this.filterOptions.filter(value=> value.key !== 'all').forEach(value =>{
|
this.filterOptions.filter(value => value.key !== 'all').forEach(value => {
|
||||||
if(!value.checked) {
|
if (!value.checked) {
|
||||||
selectAll = false;
|
selectAll = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.filterOptions.find(value=>value.key === 'all').checked = selectAll;
|
this.filterOptions.find(value => value.key === 'all').checked = selectAll;
|
||||||
}
|
}
|
||||||
this.doSearchByOptions();
|
this.doSearchByOptions();
|
||||||
}
|
}
|
||||||
|
@ -487,8 +487,9 @@
|
|||||||
"FOOT_OF": "of"
|
"FOOT_OF": "of"
|
||||||
},
|
},
|
||||||
"CHART": {
|
"CHART": {
|
||||||
"SCANNING_TIME": "Scan completed datetime",
|
"SCANNING_TIME": "Scan completed time:",
|
||||||
"TOOLTIPS_TITLE": "This image includes {{totalPackages}} {{package}} with {{vulnerability}} in {{totalVulnerability}} of the {{packageExt}}."
|
"TOOLTIPS_TITLE": "{{totalVulnerability}} of {{totalPackages}} {{package}} have known {{vulnerability}}.",
|
||||||
|
"TOOLTIPS_TITLE_SINGULAR": "{{totalVulnerability}} of {{totalPackages}} {{package}} has known {{vulnerability}}."
|
||||||
},
|
},
|
||||||
"SEVERITY": {
|
"SEVERITY": {
|
||||||
"HIGH": "high",
|
"HIGH": "high",
|
||||||
|
@ -486,8 +486,9 @@
|
|||||||
"FOOT_OF": "of"
|
"FOOT_OF": "of"
|
||||||
},
|
},
|
||||||
"CHART": {
|
"CHART": {
|
||||||
"SCANNING_TIME": "Scan completed datetime",
|
"SCANNING_TIME": "Scan completed time:",
|
||||||
"TOOLTIPS_TITLE": "This image includes {{totalPackages}} {{package}} with {{vulnerability}} in {{totalVulnerability}} of the {{packageExt}}."
|
"TOOLTIPS_TITLE": "{{totalVulnerability}} of {{totalPackages}} {{package}} have known {{vulnerability}}.",
|
||||||
|
"TOOLTIPS_TITLE_SINGULAR": "{{totalVulnerability}} of {{totalPackages}} {{package}} has known {{vulnerability}}."
|
||||||
},
|
},
|
||||||
"SEVERITY": {
|
"SEVERITY": {
|
||||||
"HIGH": "high",
|
"HIGH": "high",
|
||||||
|
@ -487,8 +487,9 @@
|
|||||||
"FOOT_OF": "总共"
|
"FOOT_OF": "总共"
|
||||||
},
|
},
|
||||||
"CHART": {
|
"CHART": {
|
||||||
"SCANNING_TIME": "扫描完成",
|
"SCANNING_TIME": "扫描完成时间:",
|
||||||
"TOOLTIPS_TITLE": "在此镜像总共包含{{totalPackages}}{{package}},其中{{totalVulnerability}}个{{packageExt}}含有{{vulnerability}}。"
|
"TOOLTIPS_TITLE": "{{totalPackages}}个{{package}}中的{{totalVulnerability}}个含有{{vulnerability}}.",
|
||||||
|
"TOOLTIPS_TITLE_SINGULAR": "{{totalPackages}}个{{package}}中的{{totalVulnerability}}个含有{{vulnerability}}."
|
||||||
},
|
},
|
||||||
"SEVERITY": {
|
"SEVERITY": {
|
||||||
"HIGH": "严重",
|
"HIGH": "严重",
|
||||||
|
Loading…
Reference in New Issue
Block a user