mirror of
https://github.com/goharbor/harbor.git
synced 2024-12-27 02:58:05 +01:00
Add pagination support to scanner list (#14673)
Signed-off-by: AllForNothing <sshijun@vmware.com>
This commit is contained in:
parent
5e75c45873
commit
5e5544cd47
@ -8,7 +8,6 @@ import { SearchTriggerService } from '../../shared/components/global-search/sear
|
||||
import { HarborShellComponent } from './harbor-shell.component';
|
||||
import { ClarityModule } from "@clr/angular";
|
||||
import { of } from 'rxjs';
|
||||
import { ConfigScannerService } from "../left-side-nav/interrogation-services/scanner/config-scanner.service";
|
||||
import { modalEvents } from '../modal-events.const';
|
||||
import { PasswordSettingComponent } from '../password-setting/password-setting.component';
|
||||
import { AboutDialogComponent } from '../../shared/components/about-dialog/about-dialog.component';
|
||||
@ -21,6 +20,10 @@ import { ErrorHandler } from '../../shared/units/error-handler';
|
||||
import { AccountSettingsModalComponent } from "../account-settings/account-settings-modal.component";
|
||||
import { InlineAlertComponent } from "../../shared/components/inline-alert/inline-alert.component";
|
||||
import { AccountSettingsModalService } from "../account-settings/account-settings-modal-service.service";
|
||||
import { ScannerService } from "../../../../ng-swagger-gen/services/scanner.service";
|
||||
import { HttpHeaders, HttpResponse } from "@angular/common/http";
|
||||
import { Registry } from "../../../../ng-swagger-gen/models/registry";
|
||||
import { delay } from "rxjs/operators";
|
||||
|
||||
describe('HarborShellComponent', () => {
|
||||
let component: HarborShellComponent;
|
||||
@ -71,9 +74,16 @@ describe('HarborShellComponent', () => {
|
||||
};
|
||||
}
|
||||
};
|
||||
let fakeConfigScannerService = {
|
||||
getScanners() {
|
||||
return of(true);
|
||||
let fakeScannerService = {
|
||||
listScannersResponse() {
|
||||
const response: HttpResponse<Array<Registry>> = new HttpResponse<Array<Registry>>({
|
||||
headers: new HttpHeaders({'x-total-count': [].length.toString()}),
|
||||
body: []
|
||||
});
|
||||
return of(response).pipe(delay(0));
|
||||
},
|
||||
listScanners() {
|
||||
return of([]).pipe(delay(0));
|
||||
}
|
||||
};
|
||||
beforeEach(waitForAsync(() => {
|
||||
@ -92,7 +102,7 @@ describe('HarborShellComponent', () => {
|
||||
{ provide: SessionService, useValue: fakeSessionService },
|
||||
{ provide: SearchTriggerService, useValue: fakeSearchTriggerService },
|
||||
{ provide: AppConfigService, useValue: fakeAppConfigService },
|
||||
{ provide: ConfigScannerService, useValue: fakeConfigScannerService },
|
||||
{ provide: ScannerService, useValue: fakeScannerService },
|
||||
{ provide: MessageHandlerService, useValue: mockMessageHandlerService },
|
||||
{ provide: AccountSettingsModalService, useValue: mockAccountSettingsModalService },
|
||||
{ provide: PasswordSettingService, useValue: mockPasswordSettingService },
|
||||
|
@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
import { Component, OnInit, ViewChild, OnDestroy, ElementRef, ChangeDetectorRef } from '@angular/core';
|
||||
import { Router, ActivatedRoute } from '@angular/router';
|
||||
import { Subscription } from "rxjs";
|
||||
import { forkJoin, Observable, Subscription } from "rxjs";
|
||||
import { AppConfigService } from '../../services/app-config.service';
|
||||
import { ModalEvent } from '../modal-event';
|
||||
import { modalEvents } from '../modal-events.const';
|
||||
@ -23,12 +23,14 @@ import { SessionService } from '../../shared/services/session.service';
|
||||
import { AboutDialogComponent } from '../../shared/components/about-dialog/about-dialog.component';
|
||||
import { SearchTriggerService } from '../../shared/components/global-search/search-trigger.service';
|
||||
import { CommonRoutes } from "../../shared/entities/shared.const";
|
||||
import { ConfigScannerService, SCANNERS_DOC } from "../left-side-nav/interrogation-services/scanner/config-scanner.service";
|
||||
import { THEME_ARRAY, ThemeInterface } from "../../services/theme";
|
||||
import { clone } from "../../shared/units/utils";
|
||||
import { clone, DEFAULT_PAGE_SIZE } from "../../shared/units/utils";
|
||||
import { ThemeService } from "../../services/theme.service";
|
||||
import { AccountSettingsModalComponent } from "../account-settings/account-settings-modal.component";
|
||||
import { EventService, HarborEvent } from "../../services/event-service/event.service";
|
||||
import { SCANNERS_DOC } from "../left-side-nav/interrogation-services/scanner/scanner";
|
||||
import { ScannerService } from "../../../../ng-swagger-gen/services/scanner.service";
|
||||
import { Project } from "../../../../ng-swagger-gen/models/project";
|
||||
|
||||
const HAS_SHOWED_SCANNER_INFO: string = 'hasShowScannerInfo';
|
||||
const YES: string = 'yes';
|
||||
@ -76,7 +78,7 @@ export class HarborShellComponent implements OnInit, OnDestroy {
|
||||
private session: SessionService,
|
||||
private searchTrigger: SearchTriggerService,
|
||||
private appConfigService: AppConfigService,
|
||||
private scannerService: ConfigScannerService,
|
||||
private scannerService: ScannerService,
|
||||
public theme: ThemeService,
|
||||
private event: EventService,
|
||||
private cd: ChangeDetectorRef
|
||||
@ -108,7 +110,9 @@ export class HarborShellComponent implements OnInit, OnDestroy {
|
||||
this.isSearchResultsOpened = false;
|
||||
});
|
||||
if (!(localStorage && localStorage.getItem(HAS_SHOWED_SCANNER_INFO) === YES)) {
|
||||
this.getDefaultScanner();
|
||||
if (this.isSystemAdmin) {
|
||||
this.getDefaultScanner();
|
||||
}
|
||||
}
|
||||
// set local in app
|
||||
if (localStorage) {
|
||||
@ -131,11 +135,37 @@ export class HarborShellComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
getDefaultScanner() {
|
||||
this.scannerService.getScanners()
|
||||
.subscribe(scanners => {
|
||||
if (scanners && scanners.length) {
|
||||
this.showScannerInfo = scanners.some(scanner => scanner.is_default);
|
||||
}
|
||||
this.scannerService.listScannersResponse({
|
||||
pageSize: DEFAULT_PAGE_SIZE,
|
||||
page: 1
|
||||
}).subscribe(res => {
|
||||
if (res.headers) {
|
||||
const xHeader: string = res.headers.get("X-Total-Count");
|
||||
const totalCount = parseInt(xHeader, 0);
|
||||
let arr = res.body || [];
|
||||
if (totalCount <= DEFAULT_PAGE_SIZE) { // already gotten all scanners
|
||||
if (arr && arr.length) {
|
||||
this.showScannerInfo = arr.some(scanner => scanner.is_default);
|
||||
}
|
||||
} else { // get all the scanners in specified times
|
||||
const times: number = Math.ceil(totalCount / DEFAULT_PAGE_SIZE);
|
||||
const observableList: Observable<Project[]>[] = [];
|
||||
for (let i = 2; i <= times; i++) {
|
||||
observableList.push(this.scannerService.listScanners({
|
||||
page: i,
|
||||
pageSize: DEFAULT_PAGE_SIZE
|
||||
}));
|
||||
}
|
||||
forkJoin(observableList).subscribe(response => {
|
||||
if (response && response.length) {
|
||||
response.forEach(item => {
|
||||
arr = arr.concat(item);
|
||||
});
|
||||
this.showScannerInfo = arr.some(scanner => scanner.is_default);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
ngOnDestroy(): void {
|
||||
|
@ -17,7 +17,6 @@ import { SharedModule } from "../../../shared/shared.module";
|
||||
import { NewScannerModalComponent } from "./scanner/new-scanner-modal/new-scanner-modal.component";
|
||||
import { ScannerMetadataComponent } from "./scanner/scanner-metadata/scanner-metadata.component";
|
||||
import { NewScannerFormComponent } from "./scanner/new-scanner-form/new-scanner-form.component";
|
||||
import { ConfigScannerService } from "./scanner/config-scanner.service";
|
||||
import { RouterModule, Routes } from "@angular/router";
|
||||
import { ConfigurationScannerComponent } from "./scanner/config-scanner.component";
|
||||
import { VulnerabilityConfigComponent } from "./vulnerability/vulnerability-config.component";
|
||||
@ -61,7 +60,6 @@ const routes: Routes = [
|
||||
VulnerabilityConfigComponent
|
||||
],
|
||||
providers: [
|
||||
ConfigScannerService,
|
||||
ScanAllRepoService,
|
||||
{provide: ScanApiRepository, useClass: ScanApiDefaultRepository },
|
||||
]
|
||||
|
@ -8,7 +8,7 @@
|
||||
</clr-signpost-content>
|
||||
</clr-signpost>
|
||||
</h4>
|
||||
<clr-datagrid [clrDgLoading]="onGoing" [(clrDgSingleSelected)]="selectedRow">
|
||||
<clr-datagrid (clrDgRefresh)="getScanners($event)" [clrDgLoading]="onGoing" [(clrDgSingleSelected)]="selectedRow">
|
||||
<clr-dg-action-bar>
|
||||
<div class="clr-row">
|
||||
<div class="clr-col-7">
|
||||
@ -52,7 +52,7 @@
|
||||
</div>
|
||||
<div class="clr-col-5">
|
||||
<div class="action-head-pos">
|
||||
<span (click)="getScanners()" class="refresh-btn">
|
||||
<span (click)="refresh()" class="refresh-btn">
|
||||
<clr-icon shape="refresh" [hidden]="onGoing"></clr-icon>
|
||||
</span>
|
||||
</div>
|
||||
@ -67,7 +67,7 @@
|
||||
<clr-dg-placeholder>
|
||||
{{'SCANNER.NO_SCANNER' | translate}}
|
||||
</clr-dg-placeholder>
|
||||
<clr-dg-row *clrDgItems="let scanner of scanners" [clrDgItem]="scanner">
|
||||
<clr-dg-row *ngFor="let scanner of scanners" [clrDgItem]="scanner">
|
||||
<clr-dg-cell class="position-relative">
|
||||
<span>{{scanner.name}}</span>
|
||||
<span *ngIf="scanner.is_default" class="label label-info ml-1">{{'SCANNER.DEFAULT' | translate}}</span>
|
||||
@ -96,9 +96,10 @@
|
||||
<scanner-metadata *clrIfExpanded [uid]="scanner.uuid" ngProjectAs="clr-dg-row-detail"></scanner-metadata>
|
||||
</clr-dg-row>
|
||||
<clr-dg-footer>
|
||||
<clr-dg-pagination [clrDgPageSize]="15">
|
||||
<clr-dg-pagination #pagination [clrDgPageSize]="pageSize" [(clrDgPage)]="page" [clrDgTotalItems]="total">
|
||||
<clr-dg-page-size [clrPageSizeOptions]="[15,25,50]">{{"PAGINATION.PAGE_SIZE" | translate}}</clr-dg-page-size>
|
||||
<span *ngIf="scanners?.length > 0">1 - {{scanners?.length}} {{'WEBHOOK.OF' | translate}} </span> {{scanners?.length}} {{'WEBHOOK.ITEMS' | translate}}
|
||||
<span *ngIf="total">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'DESTINATION.OF' | translate}}</span>
|
||||
{{total}} {{'DESTINATION.ITEMS' | translate}}
|
||||
</clr-dg-pagination>
|
||||
</clr-dg-footer>
|
||||
</clr-datagrid>
|
||||
|
@ -1,17 +1,15 @@
|
||||
import { ComponentFixture, ComponentFixtureAutoDetect, TestBed } from '@angular/core/testing';
|
||||
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
|
||||
import { ClarityModule } from "@clr/angular";
|
||||
import { of } from "rxjs";
|
||||
import { delay } from "rxjs/operators";
|
||||
import { ConfigurationScannerComponent } from "./config-scanner.component";
|
||||
import { ConfigScannerService } from "./config-scanner.service";
|
||||
import { MessageHandlerService } from "../../../../shared/services/message-handler.service";
|
||||
import { SharedTestingModule } from "../../../../shared/shared.module";
|
||||
import { ScannerMetadataComponent } from "./scanner-metadata/scanner-metadata.component";
|
||||
import { NewScannerModalComponent } from "./new-scanner-modal/new-scanner-modal.component";
|
||||
import { NewScannerFormComponent } from "./new-scanner-form/new-scanner-form.component";
|
||||
import { TranslateService } from "@ngx-translate/core";
|
||||
import { ErrorHandler } from "../../../../shared/units/error-handler";
|
||||
import { ConfirmationDialogService } from "../../../global-confirmation-dialog/confirmation-dialog.service";
|
||||
import { ScannerService } from "../../../../../../ng-swagger-gen/services/scanner.service";
|
||||
import { HttpHeaders, HttpResponse } from "@angular/common/http";
|
||||
import { Registry } from "../../../../../../ng-swagger-gen/models/registry";
|
||||
import { ClrLoadingState } from "@clr/angular";
|
||||
|
||||
describe('ConfigurationScannerComponent', () => {
|
||||
let mockScannerMetadata = {
|
||||
@ -35,10 +33,14 @@ describe('ConfigurationScannerComponent', () => {
|
||||
let fixture: ComponentFixture<ConfigurationScannerComponent>;
|
||||
let fakedConfigScannerService = {
|
||||
getScannerMetadata() {
|
||||
return of(mockScannerMetadata);
|
||||
return of(mockScannerMetadata).pipe(delay(10));
|
||||
},
|
||||
getScanners() {
|
||||
return of([mockScanner1]);
|
||||
listScannersResponse() {
|
||||
const response: HttpResponse<Array<Registry>> = new HttpResponse<Array<Registry>>({
|
||||
headers: new HttpHeaders({'x-total-count': [mockScanner1].length.toString()}),
|
||||
body: [mockScanner1]
|
||||
});
|
||||
return of(response).pipe(delay(10));
|
||||
},
|
||||
updateScanner() {
|
||||
return of(true);
|
||||
@ -48,8 +50,6 @@ describe('ConfigurationScannerComponent', () => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
SharedTestingModule,
|
||||
BrowserAnimationsModule,
|
||||
ClarityModule,
|
||||
],
|
||||
declarations: [
|
||||
ConfigurationScannerComponent,
|
||||
@ -58,11 +58,7 @@ describe('ConfigurationScannerComponent', () => {
|
||||
NewScannerFormComponent
|
||||
],
|
||||
providers: [
|
||||
ErrorHandler,
|
||||
MessageHandlerService,
|
||||
ConfirmationDialogService,
|
||||
TranslateService,
|
||||
{ provide: ConfigScannerService, useValue: fakedConfigScannerService },
|
||||
{ provide: ScannerService, useValue: fakedConfigScannerService },
|
||||
// open auto detect
|
||||
{ provide: ComponentFixtureAutoDetect, useValue: true }
|
||||
]
|
||||
@ -71,9 +67,11 @@ describe('ConfigurationScannerComponent', () => {
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ConfigurationScannerComponent);
|
||||
component = fixture.componentInstance;
|
||||
component.newScannerDialog.saveBtnState = ClrLoadingState.LOADING;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
it('should create', () => {
|
||||
it('should create', async () => {
|
||||
await fixture.whenStable();
|
||||
expect(component).toBeTruthy();
|
||||
expect(component.scanners.length).toBe(1);
|
||||
});
|
||||
|
@ -1,14 +1,16 @@
|
||||
import { Component, ViewChild, OnInit, OnDestroy } from "@angular/core";
|
||||
import { Scanner } from "./scanner";
|
||||
import { Scanner, SCANNERS_DOC } from "./scanner";
|
||||
import { NewScannerModalComponent } from "./new-scanner-modal/new-scanner-modal.component";
|
||||
import { ConfigScannerService, SCANNERS_DOC } from "./config-scanner.service";
|
||||
import { finalize } from "rxjs/operators";
|
||||
import { MessageHandlerService } from "../../../../shared/services/message-handler.service";
|
||||
import { ErrorHandler } from "../../../../shared/units/error-handler";
|
||||
import { clone } from "../../../../shared/units/utils";
|
||||
import { clone, DEFAULT_PAGE_SIZE, getSortingString } from "../../../../shared/units/utils";
|
||||
import { ConfirmationDialogService } from "../../../global-confirmation-dialog/confirmation-dialog.service";
|
||||
import { ConfirmationButtons, ConfirmationState, ConfirmationTargets } from "../../../../shared/entities/shared.const";
|
||||
import { ConfirmationMessage } from "../../../global-confirmation-dialog/confirmation-message";
|
||||
import { ScannerService } from "../../../../../../ng-swagger-gen/services/scanner.service";
|
||||
import { ClrDatagridStateInterface } from "@clr/angular";
|
||||
import { ScannerRegistrationReq } from "../../../../../../ng-swagger-gen/models/scanner-registration-req";
|
||||
|
||||
@Component({
|
||||
selector: 'config-scanner',
|
||||
@ -18,13 +20,17 @@ import { ConfirmationMessage } from "../../../global-confirmation-dialog/confirm
|
||||
export class ConfigurationScannerComponent implements OnInit, OnDestroy {
|
||||
scanners: Scanner[] = [];
|
||||
selectedRow: Scanner;
|
||||
onGoing: boolean = false;
|
||||
onGoing: boolean = true;
|
||||
@ViewChild(NewScannerModalComponent)
|
||||
newScannerDialog: NewScannerModalComponent;
|
||||
deletionSubscription: any;
|
||||
scannerDocUrl: string = SCANNERS_DOC;
|
||||
page: number = 1;
|
||||
pageSize: number = DEFAULT_PAGE_SIZE;
|
||||
total: number = 0;
|
||||
state: ClrDatagridStateInterface;
|
||||
constructor(
|
||||
private configScannerService: ConfigScannerService,
|
||||
private configScannerService: ScannerService,
|
||||
private errorHandler: ErrorHandler,
|
||||
private msgHandler: MessageHandlerService,
|
||||
private deletionDialogService: ConfirmationDialogService,
|
||||
@ -35,17 +41,18 @@ export class ConfigurationScannerComponent implements OnInit, OnDestroy {
|
||||
if (confirmed &&
|
||||
confirmed.source === ConfirmationTargets.SCANNER &&
|
||||
confirmed.state === ConfirmationState.CONFIRMED) {
|
||||
this.configScannerService.deleteScanners(confirmed.data)
|
||||
this.configScannerService.deleteScanner({
|
||||
registrationId: confirmed.data[0].uuid
|
||||
})
|
||||
.subscribe(response => {
|
||||
this.msgHandler.showSuccess("SCANNER.DELETE_SUCCESS");
|
||||
this.getScanners();
|
||||
this.refresh();
|
||||
}, error => {
|
||||
this.errorHandler.error(error);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
this.getScanners();
|
||||
}
|
||||
ngOnDestroy(): void {
|
||||
if (this.deletionSubscription) {
|
||||
@ -53,13 +60,45 @@ export class ConfigurationScannerComponent implements OnInit, OnDestroy {
|
||||
this.deletionSubscription = null;
|
||||
}
|
||||
}
|
||||
getScanners() {
|
||||
refresh() {
|
||||
this.page = 1;
|
||||
this.selectedRow = null;
|
||||
this.total = 0;
|
||||
this.getScanners(this.state);
|
||||
}
|
||||
getScanners(state?: ClrDatagridStateInterface) {
|
||||
this.state = state;
|
||||
if (state && state.page) {
|
||||
this.pageSize = state.page.size;
|
||||
}
|
||||
let q: string;
|
||||
if (state && state.filters && state.filters.length) {
|
||||
q = encodeURIComponent(`${state.filters[0].property}=~${state.filters[0].value}`);
|
||||
}
|
||||
let sort: string;
|
||||
if (state && state.sort && state.sort.by) {
|
||||
sort = getSortingString(state);
|
||||
} else { // sort by creation_time desc by default
|
||||
sort = `-creation_time`;
|
||||
}
|
||||
this.onGoing = true;
|
||||
this.configScannerService.getScanners()
|
||||
this.configScannerService.listScannersResponse({
|
||||
page: this.page,
|
||||
pageSize: this.pageSize,
|
||||
q: q,
|
||||
sort: sort
|
||||
})
|
||||
.pipe(finalize(() => this.onGoing = false))
|
||||
.subscribe(response => {
|
||||
this.scanners = response;
|
||||
this.getMetadataForAll();
|
||||
// Get total count
|
||||
if (response.headers) {
|
||||
let xHeader: string = response.headers.get("X-Total-Count");
|
||||
if (xHeader) {
|
||||
this.total = parseInt(xHeader, 0);
|
||||
}
|
||||
}
|
||||
this.scanners = response.body || [];
|
||||
this.getMetadataForAll();
|
||||
}, error => {
|
||||
this.errorHandler.error(error);
|
||||
});
|
||||
@ -69,7 +108,9 @@ export class ConfigurationScannerComponent implements OnInit, OnDestroy {
|
||||
this.scanners.forEach((scanner, index) => {
|
||||
if (scanner.uuid ) {
|
||||
this.scanners[index].loadingMetadata = true;
|
||||
this.configScannerService.getScannerMetadata(scanner.uuid)
|
||||
this.configScannerService.getScannerMetadata({
|
||||
registrationId: scanner.uuid
|
||||
})
|
||||
.pipe(finalize(() => this.scanners[index].loadingMetadata = false))
|
||||
.subscribe(response => {
|
||||
this.scanners[index].metadata = response;
|
||||
@ -91,12 +132,15 @@ export class ConfigurationScannerComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
changeStat() {
|
||||
if (this.selectedRow) {
|
||||
let scanner: Scanner = clone(this.selectedRow);
|
||||
let scanner: ScannerRegistrationReq = clone(this.selectedRow);
|
||||
scanner.disabled = !scanner.disabled;
|
||||
this.configScannerService.updateScanner(scanner)
|
||||
this.configScannerService.updateScanner({
|
||||
registrationId: this.selectedRow.uuid,
|
||||
registration: scanner
|
||||
})
|
||||
.subscribe(response => {
|
||||
this.msgHandler.showSuccess("SCANNER.UPDATE_SUCCESS");
|
||||
this.getScanners();
|
||||
this.refresh();
|
||||
}, error => {
|
||||
this.errorHandler.error(error);
|
||||
});
|
||||
@ -104,10 +148,15 @@ export class ConfigurationScannerComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
setAsDefault() {
|
||||
if (this.selectedRow) {
|
||||
this.configScannerService.setAsDefault(this.selectedRow.uuid)
|
||||
this.configScannerService.setScannerAsDefault({
|
||||
registrationId: this.selectedRow.uuid,
|
||||
payload: {
|
||||
is_default: true
|
||||
}
|
||||
})
|
||||
.subscribe(response => {
|
||||
this.msgHandler.showSuccess("SCANNER.UPDATE_SUCCESS");
|
||||
this.getScanners();
|
||||
this.refresh();
|
||||
}, error => {
|
||||
this.errorHandler.error(error);
|
||||
});
|
||||
|
@ -1,20 +0,0 @@
|
||||
import { TestBed, inject } from '@angular/core/testing';
|
||||
import { SharedTestingModule } from "../../../../shared/shared.module";
|
||||
import { ConfigScannerService } from "./config-scanner.service";
|
||||
|
||||
describe('TagService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
SharedTestingModule
|
||||
],
|
||||
providers: [
|
||||
ConfigScannerService
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
it('should be initialized', inject([ConfigScannerService], (service: ConfigScannerService) => {
|
||||
expect(service).toBeTruthy();
|
||||
}));
|
||||
});
|
@ -1,82 +0,0 @@
|
||||
import {Injectable} from "@angular/core";
|
||||
import {Scanner} from "./scanner";
|
||||
import { forkJoin, Observable, throwError as observableThrowError } from "rxjs";
|
||||
import { catchError, map } from "rxjs/operators";
|
||||
import { HttpClient } from "@angular/common/http";
|
||||
import { ScannerMetadata } from "./scanner-metadata";
|
||||
import { CURRENT_BASE_HREF } from "../../../../shared/units/utils";
|
||||
|
||||
export const SCANNERS_DOC: string = "https://goharbor.io/blog/harbor-1.10-release/#vulnerability-scanning-with-pluggable-scanners";
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class ConfigScannerService {
|
||||
|
||||
constructor( private http: HttpClient) {}
|
||||
getScannersByName(name: string): Observable<Scanner[]> {
|
||||
name = encodeURIComponent(name);
|
||||
return this.http.get(`${ CURRENT_BASE_HREF }/scanners?ex_name=${name}`)
|
||||
.pipe(catchError(error => observableThrowError(error)))
|
||||
.pipe(map(response => response as Scanner[]));
|
||||
}
|
||||
getScannersByEndpointUrl(endpointUrl: string): Observable<Scanner[]> {
|
||||
endpointUrl = encodeURIComponent(endpointUrl);
|
||||
return this.http.get(`${ CURRENT_BASE_HREF }/scanners?ex_url=${endpointUrl}`)
|
||||
.pipe(catchError(error => observableThrowError(error)))
|
||||
.pipe(map(response => response as Scanner[]));
|
||||
}
|
||||
testEndpointUrl(testValue: any): Observable<any> {
|
||||
return this.http.post(`${ CURRENT_BASE_HREF }/scanners/ping`, testValue)
|
||||
.pipe(catchError(error => observableThrowError(error)));
|
||||
}
|
||||
addScanner(scanner: Scanner): Observable<any> {
|
||||
return this.http.post(CURRENT_BASE_HREF + '/scanners', scanner )
|
||||
.pipe(catchError(error => observableThrowError(error)));
|
||||
}
|
||||
getScanners(): Observable<Scanner[]> {
|
||||
return this.http.get(CURRENT_BASE_HREF + '/scanners')
|
||||
.pipe(map(response => response as Scanner[]))
|
||||
.pipe(catchError(error => observableThrowError(error)));
|
||||
}
|
||||
updateScanner(scanner: Scanner): Observable<any> {
|
||||
return this.http.put(`${ CURRENT_BASE_HREF }/scanners/${scanner.uuid}`, scanner )
|
||||
.pipe(catchError(error => observableThrowError(error)));
|
||||
}
|
||||
deleteScanner(scanner: Scanner): Observable<any> {
|
||||
return this.http.delete(`${ CURRENT_BASE_HREF }/scanners/${scanner.uuid}`)
|
||||
.pipe(catchError(error => observableThrowError(error)));
|
||||
}
|
||||
deleteScanners(scanners: Scanner[]): Observable<any> {
|
||||
let observableLists: any[] = [];
|
||||
if (scanners && scanners.length > 0) {
|
||||
scanners.forEach(scanner => {
|
||||
observableLists.push(this.deleteScanner(scanner));
|
||||
});
|
||||
return forkJoin(...observableLists);
|
||||
}
|
||||
}
|
||||
getProjectScanner(projectId: number): Observable<Scanner> {
|
||||
return this.http.get(`${ CURRENT_BASE_HREF }/projects/${projectId}/scanner`)
|
||||
.pipe(map(response => response as Scanner))
|
||||
.pipe(catchError(error => observableThrowError(error)));
|
||||
}
|
||||
updateProjectScanner(projectId: number , uid: string): Observable<any> {
|
||||
return this.http.put(`${ CURRENT_BASE_HREF }/projects/${projectId}/scanner` , {uuid: uid})
|
||||
.pipe(catchError(error => observableThrowError(error)));
|
||||
}
|
||||
getScannerMetadata(uid: string): Observable<ScannerMetadata> {
|
||||
return this.http.get(`${ CURRENT_BASE_HREF }/scanners/${uid}/metadata`)
|
||||
.pipe(map(response => response as ScannerMetadata))
|
||||
.pipe(catchError(error => observableThrowError(error)));
|
||||
}
|
||||
setAsDefault(uid: string): Observable<any> {
|
||||
return this.http.patch(`${ CURRENT_BASE_HREF }/scanners/${uid}`, {is_default: true} )
|
||||
.pipe(catchError(error => observableThrowError(error)));
|
||||
}
|
||||
getProjectScanners(projectId: number) {
|
||||
return this.http.get(`${ CURRENT_BASE_HREF }/projects/${projectId}/scanner/candidates`)
|
||||
.pipe(map(response => response as Scanner[]))
|
||||
.pipe(catchError(error => observableThrowError(error)));
|
||||
}
|
||||
}
|
@ -4,10 +4,10 @@ import { FormBuilder } from "@angular/forms";
|
||||
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
|
||||
import { ClarityModule } from "@clr/angular";
|
||||
import { SharedTestingModule } from "../../../../../shared/shared.module";
|
||||
import { ConfigScannerService } from "../config-scanner.service";
|
||||
import { of } from "rxjs";
|
||||
import { TranslateService } from "@ngx-translate/core";
|
||||
import { delay } from "rxjs/operators";
|
||||
import { ScannerService } from "../../../../../../../ng-swagger-gen/services/scanner.service";
|
||||
|
||||
describe('NewScannerFormComponent', () => {
|
||||
let mockScanner1 = {
|
||||
@ -19,7 +19,7 @@ describe('NewScannerFormComponent', () => {
|
||||
let component: NewScannerFormComponent;
|
||||
let fixture: ComponentFixture<NewScannerFormComponent>;
|
||||
let fakedConfigScannerService = {
|
||||
getScannersByName() {
|
||||
listScanners() {
|
||||
return of([mockScanner1]).pipe(delay(500));
|
||||
},
|
||||
getScannersByEndpointUrl() {
|
||||
@ -37,7 +37,7 @@ describe('NewScannerFormComponent', () => {
|
||||
providers: [
|
||||
FormBuilder,
|
||||
TranslateService,
|
||||
{ provide: ConfigScannerService, useValue: fakedConfigScannerService },
|
||||
{ provide: ScannerService, useValue: fakedConfigScannerService },
|
||||
// open auto detect
|
||||
{ provide: ComponentFixtureAutoDetect, useValue: true }
|
||||
]
|
||||
|
@ -9,7 +9,7 @@ import {
|
||||
import { FormBuilder, FormGroup, Validators } from "@angular/forms";
|
||||
import { fromEvent } from "rxjs";
|
||||
import { debounceTime, distinctUntilChanged, filter, finalize, map, switchMap } from "rxjs/operators";
|
||||
import { ConfigScannerService } from "../config-scanner.service";
|
||||
import { ScannerService } from "../../../../../../../ng-swagger-gen/services/scanner.service";
|
||||
|
||||
|
||||
@Component({
|
||||
@ -48,7 +48,7 @@ export class NewScannerFormComponent implements OnInit, AfterViewInit, OnDestro
|
||||
isEdit: boolean;
|
||||
@ViewChild('name') scannerName: ElementRef;
|
||||
@ViewChild('endpointUrl') scannerEndpointUrl: ElementRef;
|
||||
constructor(private fb: FormBuilder, private scannerService: ConfigScannerService) {
|
||||
constructor(private fb: FormBuilder, private scannerService: ScannerService) {
|
||||
}
|
||||
ngAfterViewInit(): void {
|
||||
if (!this.checkNameSubscribe) {
|
||||
@ -65,7 +65,9 @@ export class NewScannerFormComponent implements OnInit, AfterViewInit, OnDestro
|
||||
switchMap((name) => {
|
||||
this.isNameExisting = false;
|
||||
this.checkOnGoing = true;
|
||||
return this.scannerService.getScannersByName(name)
|
||||
return this.scannerService.listScanners({
|
||||
q: encodeURIComponent(`name=${name}`)
|
||||
})
|
||||
.pipe(finalize(() => this.checkOnGoing = false));
|
||||
})).subscribe(response => {
|
||||
if (response && response.length > 0) {
|
||||
@ -94,7 +96,9 @@ export class NewScannerFormComponent implements OnInit, AfterViewInit, OnDestro
|
||||
switchMap((endpointUrl) => {
|
||||
this.isEndpointUrlExisting = false;
|
||||
this.checkEndpointOnGoing = true;
|
||||
return this.scannerService.getScannersByEndpointUrl(endpointUrl)
|
||||
return this.scannerService.listScanners({
|
||||
q: encodeURIComponent(`url=${endpointUrl}`)
|
||||
})
|
||||
.pipe(finalize(() => this.checkEndpointOnGoing = false));
|
||||
})).subscribe(response => {
|
||||
if (response && response.length > 0) {
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { ComponentFixture, ComponentFixtureAutoDetect, fakeAsync, TestBed, tick } from '@angular/core/testing';
|
||||
import { ClrLoadingState } from "@clr/angular";
|
||||
import { ConfigScannerService } from "../config-scanner.service";
|
||||
import { NewScannerModalComponent } from "./new-scanner-modal.component";
|
||||
import { MessageHandlerService } from "../../../../../shared/services/message-handler.service";
|
||||
import { NewScannerFormComponent } from "../new-scanner-form/new-scanner-form.component";
|
||||
@ -9,6 +8,7 @@ import { of, Subscription } from "rxjs";
|
||||
import { delay } from "rxjs/operators";
|
||||
import { SharedTestingModule } from "../../../../../shared/shared.module";
|
||||
import { Scanner } from "../scanner";
|
||||
import { ScannerService } from "../../../../../../../ng-swagger-gen/services/scanner.service";
|
||||
|
||||
describe('NewScannerModalComponent', () => {
|
||||
let component: NewScannerModalComponent;
|
||||
@ -21,13 +21,13 @@ describe('NewScannerModalComponent', () => {
|
||||
auth: "",
|
||||
};
|
||||
let fakedConfigScannerService = {
|
||||
getScannersByName() {
|
||||
listScanners() {
|
||||
return of([mockScanner1]);
|
||||
},
|
||||
testEndpointUrl() {
|
||||
pingScanner() {
|
||||
return of(true).pipe(delay(200));
|
||||
},
|
||||
addScanner() {
|
||||
createScanner() {
|
||||
return of(true).pipe(delay(200));
|
||||
},
|
||||
updateScanner() {
|
||||
@ -45,7 +45,7 @@ describe('NewScannerModalComponent', () => {
|
||||
],
|
||||
providers: [
|
||||
MessageHandlerService,
|
||||
{ provide: ConfigScannerService, useValue: fakedConfigScannerService },
|
||||
{ provide: ScannerService, useValue: fakedConfigScannerService },
|
||||
FormBuilder,
|
||||
// open auto detect
|
||||
{ provide: ComponentFixtureAutoDetect, useValue: true }
|
||||
|
@ -1,12 +1,14 @@
|
||||
import { Component, EventEmitter, Output, ViewChild } from '@angular/core';
|
||||
import { Scanner } from "../scanner";
|
||||
import { NewScannerFormComponent } from "../new-scanner-form/new-scanner-form.component";
|
||||
import { ConfigScannerService } from "../config-scanner.service";
|
||||
import { ClrLoadingState } from "@clr/angular";
|
||||
import { finalize } from "rxjs/operators";
|
||||
import { MessageHandlerService } from "../../../../../shared/services/message-handler.service";
|
||||
import { TranslateService } from "@ngx-translate/core";
|
||||
import { InlineAlertComponent } from "../../../../../shared/components/inline-alert/inline-alert.component";
|
||||
import { ScannerService } from "../../../../../../../ng-swagger-gen/services/scanner.service";
|
||||
import { ScannerRegistrationReq } from "../../../../../../../ng-swagger-gen/models/scanner-registration-req";
|
||||
import { clone } from "../../../../../shared/units/utils";
|
||||
|
||||
@Component({
|
||||
selector: "new-scanner-modal",
|
||||
@ -29,7 +31,7 @@ export class NewScannerModalComponent {
|
||||
editScanner: Scanner;
|
||||
@ViewChild(InlineAlertComponent) inlineAlert: InlineAlertComponent;
|
||||
constructor(
|
||||
private configScannerService: ConfigScannerService,
|
||||
private configScannerService: ScannerService,
|
||||
private msgHandler: MessageHandlerService,
|
||||
private translate: TranslateService,
|
||||
) {}
|
||||
@ -47,8 +49,8 @@ export class NewScannerModalComponent {
|
||||
create(): void {
|
||||
this.onSaving = true;
|
||||
this.saveBtnState = ClrLoadingState.LOADING;
|
||||
let scanner: Scanner = new Scanner();
|
||||
let value = this.newScannerFormComponent.newScannerForm.value;
|
||||
const scanner: ScannerRegistrationReq = {name: "", url: ""};
|
||||
const value = this.newScannerFormComponent.newScannerForm.value;
|
||||
scanner.name = value.name;
|
||||
scanner.description = value.description;
|
||||
scanner.url = value.url;
|
||||
@ -66,7 +68,9 @@ export class NewScannerModalComponent {
|
||||
}
|
||||
scanner.skip_certVerify = !!value.skipCertVerify;
|
||||
scanner.use_internal_addr = !!value.useInner;
|
||||
this.configScannerService.addScanner(scanner)
|
||||
this.configScannerService.createScanner({
|
||||
registration: scanner
|
||||
})
|
||||
.pipe(finalize(() => this.onSaving = false))
|
||||
.subscribe(response => {
|
||||
this.close();
|
||||
@ -176,8 +180,8 @@ export class NewScannerModalComponent {
|
||||
onTestEndpoint() {
|
||||
this.onTesting = true;
|
||||
this.checkBtnState = ClrLoadingState.LOADING;
|
||||
let scanner: Scanner = new Scanner();
|
||||
let value = this.newScannerFormComponent.newScannerForm.value;
|
||||
const scanner: ScannerRegistrationReq = {name: "", url: ""};
|
||||
const value = this.newScannerFormComponent.newScannerForm.value;
|
||||
scanner.name = value.name;
|
||||
scanner.description = value.description;
|
||||
scanner.url = value.url;
|
||||
@ -195,7 +199,9 @@ export class NewScannerModalComponent {
|
||||
}
|
||||
scanner.skip_certVerify = !!value.skipCertVerify;
|
||||
scanner.use_internal_addr = !!value.useInner;
|
||||
this.configScannerService.testEndpointUrl(scanner)
|
||||
this.configScannerService.pingScanner({
|
||||
settings: scanner
|
||||
})
|
||||
.pipe(finalize(() => this.onTesting = false))
|
||||
.subscribe(response => {
|
||||
this.inlineAlert.showInlineSuccess({
|
||||
@ -236,7 +242,11 @@ export class NewScannerModalComponent {
|
||||
this.editScanner.skip_certVerify = !!value.skipCertVerify;
|
||||
this.editScanner.use_internal_addr = !!value.useInner;
|
||||
this.editScanner.uuid = this.uid;
|
||||
this.configScannerService.updateScanner(this.editScanner)
|
||||
const scanner: ScannerRegistrationReq = clone(this.editScanner);
|
||||
this.configScannerService.updateScanner({
|
||||
registrationId: this.editScanner.uuid,
|
||||
registration: scanner
|
||||
})
|
||||
.pipe(finalize(() => this.onSaving = false))
|
||||
.subscribe(response => {
|
||||
this.close();
|
||||
|
@ -1,16 +0,0 @@
|
||||
export class ScannerMetadata {
|
||||
scanner?: {
|
||||
name?: string;
|
||||
vendor?: string;
|
||||
version?: string;
|
||||
};
|
||||
capabilities?: [{
|
||||
consumes_mime_types?: Array<string>;
|
||||
produces_mime_types?: Array<string>;
|
||||
}];
|
||||
properties?: {
|
||||
[key: string]: string;
|
||||
};
|
||||
constructor() {
|
||||
}
|
||||
}
|
@ -2,10 +2,10 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
|
||||
import { ClarityModule } from "@clr/angular";
|
||||
import { SharedTestingModule } from "../../../../../shared/shared.module";
|
||||
import { ConfigScannerService } from "../config-scanner.service";
|
||||
import { of } from "rxjs";
|
||||
import { ScannerMetadataComponent } from "./scanner-metadata.component";
|
||||
import { ErrorHandler } from "../../../../../shared/units/error-handler";
|
||||
import { ScannerService } from "../../../../../../../ng-swagger-gen/services/scanner.service";
|
||||
|
||||
describe('ScannerMetadataComponent', () => {
|
||||
let mockScannerMetadata = {
|
||||
@ -38,7 +38,7 @@ describe('ScannerMetadataComponent', () => {
|
||||
],
|
||||
providers: [
|
||||
ErrorHandler,
|
||||
{ provide: ConfigScannerService, useValue: fakedConfigScannerService },
|
||||
{ provide: ScannerService, useValue: fakedConfigScannerService },
|
||||
]
|
||||
});
|
||||
});
|
||||
|
@ -2,12 +2,12 @@ import {
|
||||
Component, Input,
|
||||
OnInit
|
||||
} from "@angular/core";
|
||||
import { ConfigScannerService } from "../config-scanner.service";
|
||||
import { finalize } from "rxjs/operators";
|
||||
import { ScannerMetadata } from "../scanner-metadata";
|
||||
import { DatePipe } from "@angular/common";
|
||||
import { ErrorHandler } from "../../../../../shared/units/error-handler";
|
||||
import {DATABASE_NEXT_UPDATE_PROPERTY, DATABASE_UPDATED_PROPERTY} from "../../../../../shared/units/utils";
|
||||
import { DATABASE_NEXT_UPDATE_PROPERTY, DATABASE_UPDATED_PROPERTY } from "../../../../../shared/units/utils";
|
||||
import { ScannerService } from "../../../../../../../ng-swagger-gen/services/scanner.service";
|
||||
import { ScannerAdapterMetadata } from "../../../../../../../ng-swagger-gen/models/scanner-adapter-metadata";
|
||||
|
||||
@Component({
|
||||
selector: 'scanner-metadata',
|
||||
@ -17,13 +17,15 @@ import {DATABASE_NEXT_UPDATE_PROPERTY, DATABASE_UPDATED_PROPERTY} from "../../..
|
||||
export class ScannerMetadataComponent implements OnInit {
|
||||
@Input() uid: string;
|
||||
loading: boolean = false;
|
||||
scannerMetadata: ScannerMetadata;
|
||||
constructor(private configScannerService: ConfigScannerService,
|
||||
scannerMetadata: ScannerAdapterMetadata;
|
||||
constructor(private configScannerService: ScannerService,
|
||||
private errorHandler: ErrorHandler) {
|
||||
}
|
||||
ngOnInit(): void {
|
||||
this.loading = true;
|
||||
this.configScannerService.getScannerMetadata(this.uid)
|
||||
this.configScannerService.getScannerMetadata({
|
||||
registrationId: this.uid
|
||||
})
|
||||
.pipe(finalize(() => this.loading = false))
|
||||
.subscribe(response => {
|
||||
this.scannerMetadata = response;
|
||||
|
@ -1,24 +1,9 @@
|
||||
import { ScannerMetadata } from "./scanner-metadata";
|
||||
import { ScannerRegistration } from "../../../../../../ng-swagger-gen/models/scanner-registration";
|
||||
import { ScannerAdapterMetadata } from "../../../../../../ng-swagger-gen/models/scanner-adapter-metadata";
|
||||
|
||||
export class Scanner {
|
||||
name?: string;
|
||||
description?: string;
|
||||
uuid?: string;
|
||||
url?: string;
|
||||
auth?: string;
|
||||
access_credential?: string;
|
||||
adapter?: string;
|
||||
disabled?: boolean;
|
||||
is_default?: boolean;
|
||||
skip_certVerify?: boolean;
|
||||
use_internal_addr?: boolean;
|
||||
create_time?: any;
|
||||
update_time?: any;
|
||||
vendor?: string;
|
||||
version?: string;
|
||||
metadata?: ScannerMetadata;
|
||||
export interface Scanner extends ScannerRegistration {
|
||||
metadata?: ScannerAdapterMetadata;
|
||||
loadingMetadata?: boolean;
|
||||
health?: string;
|
||||
constructor() {
|
||||
}
|
||||
}
|
||||
|
||||
export const SCANNERS_DOC: string = "https://goharbor.io/blog/harbor-1.10-release/#vulnerability-scanning-with-pluggable-scanners";
|
||||
|
@ -3,11 +3,13 @@ import { of } from "rxjs";
|
||||
import { TranslateService } from "@ngx-translate/core";
|
||||
import { MessageHandlerService } from "../../../shared/services/message-handler.service";
|
||||
import { ScannerComponent } from "./scanner.component";
|
||||
import { ConfigScannerService } from "../../left-side-nav/interrogation-services/scanner/config-scanner.service";
|
||||
import { SharedTestingModule } from "../../../shared/shared.module";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { Scanner } from "../../left-side-nav/interrogation-services/scanner/scanner";
|
||||
import { ErrorHandler } from "../../../shared/units/error-handler";
|
||||
import { ProjectService } from "../../../../../ng-swagger-gen/services/project.service";
|
||||
import { HttpHeaders, HttpResponse } from "@angular/common/http";
|
||||
import { Registry } from "../../../../../ng-swagger-gen/models/registry";
|
||||
|
||||
describe('ScannerComponent', () => {
|
||||
const mockScanner1: Scanner = {
|
||||
@ -28,17 +30,21 @@ describe('ScannerComponent', () => {
|
||||
};
|
||||
let component: ScannerComponent;
|
||||
let fixture: ComponentFixture<ScannerComponent>;
|
||||
let fakedConfigScannerService = {
|
||||
getProjectScanner() {
|
||||
let fakedProjectService = {
|
||||
getScannerOfProject() {
|
||||
return of(mockScanner1);
|
||||
},
|
||||
getScanners() {
|
||||
listScannerCandidatesOfProject() {
|
||||
return of([mockScanner1, mockScanner2]);
|
||||
},
|
||||
getProjectScanners() {
|
||||
return of([mockScanner1, mockScanner2]);
|
||||
listScannerCandidatesOfProjectResponse() {
|
||||
const response: HttpResponse<Array<Registry>> = new HttpResponse<Array<Registry>>({
|
||||
headers: new HttpHeaders({'x-total-count': [mockScanner1, mockScanner2].length.toString()}),
|
||||
body: [mockScanner1, mockScanner2]
|
||||
});
|
||||
return of(response);
|
||||
},
|
||||
updateProjectScanner() {
|
||||
setScannerOfProject() {
|
||||
return of(true);
|
||||
}
|
||||
};
|
||||
@ -63,8 +69,8 @@ describe('ScannerComponent', () => {
|
||||
TranslateService,
|
||||
MessageHandlerService,
|
||||
ErrorHandler,
|
||||
{provide: ActivatedRoute, useValue: fakedRoute},
|
||||
{ provide: ConfigScannerService, useValue: fakedConfigScannerService },
|
||||
{ provide: ActivatedRoute, useValue: fakedRoute },
|
||||
{ provide: ProjectService, useValue: fakedProjectService },
|
||||
]
|
||||
})
|
||||
.compileComponents();
|
||||
|
@ -12,7 +12,6 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
import { Component, OnInit, ViewChild } from "@angular/core";
|
||||
import { ConfigScannerService } from "../../left-side-nav/interrogation-services/scanner/config-scanner.service";
|
||||
import { Scanner } from "../../left-side-nav/interrogation-services/scanner/scanner";
|
||||
import { MessageHandlerService } from "../../../shared/services/message-handler.service";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
@ -22,6 +21,10 @@ import { TranslateService } from "@ngx-translate/core";
|
||||
import { ErrorHandler } from "../../../shared/units/error-handler";
|
||||
import { UserPermissionService, USERSTATICPERMISSION } from "../../../shared/services";
|
||||
import { InlineAlertComponent } from "../../../shared/components/inline-alert/inline-alert.component";
|
||||
import { ProjectService } from "../../../../../ng-swagger-gen/services/project.service";
|
||||
import { DEFAULT_PAGE_SIZE } from "../../../shared/units/utils";
|
||||
import { forkJoin, Observable } from "rxjs";
|
||||
import { Project } from "../../../../../ng-swagger-gen/models/project";
|
||||
|
||||
|
||||
@Component({
|
||||
@ -40,12 +43,12 @@ export class ScannerComponent implements OnInit {
|
||||
onSaving: boolean = false;
|
||||
hasCreatePermission: boolean = false;
|
||||
@ViewChild(InlineAlertComponent) inlineAlert: InlineAlertComponent;
|
||||
constructor( private configScannerService: ConfigScannerService,
|
||||
private msgHandler: MessageHandlerService,
|
||||
constructor( private msgHandler: MessageHandlerService,
|
||||
private errorHandler: ErrorHandler,
|
||||
private route: ActivatedRoute,
|
||||
private userPermissionService: UserPermissionService,
|
||||
private translate: TranslateService
|
||||
private translate: TranslateService,
|
||||
private projectService: ProjectService
|
||||
) {
|
||||
}
|
||||
ngOnInit() {
|
||||
@ -70,7 +73,9 @@ export class ScannerComponent implements OnInit {
|
||||
}
|
||||
getScanner(isCheckHealth?: boolean) {
|
||||
this.loading = true;
|
||||
this.configScannerService.getProjectScanner(this.projectId)
|
||||
this.projectService.getScannerOfProject({
|
||||
projectNameOrId: this.projectId.toString()
|
||||
})
|
||||
.pipe(finalize(() => this.loading = false))
|
||||
.subscribe(response => {
|
||||
if (response && "{}" !== JSON.stringify(response)) {
|
||||
@ -89,14 +94,44 @@ export class ScannerComponent implements OnInit {
|
||||
}
|
||||
getScanners() {
|
||||
if (this.projectId) {
|
||||
this.configScannerService.getProjectScanners(this.projectId)
|
||||
.subscribe(response => {
|
||||
if (response && response.length > 0) {
|
||||
this.scanners = response.filter(scanner => {
|
||||
return !scanner.disabled;
|
||||
this.projectService.listScannerCandidatesOfProjectResponse({
|
||||
projectNameOrId: this.projectId.toString(),
|
||||
page: 1,
|
||||
pageSize: DEFAULT_PAGE_SIZE
|
||||
}).subscribe(response => {
|
||||
if (response.headers) {
|
||||
const xHeader: string = response.headers.get("X-Total-Count");
|
||||
const totalCount = parseInt(xHeader, 0);
|
||||
let arr = response.body || [];
|
||||
if (totalCount <= DEFAULT_PAGE_SIZE) { // already gotten all scanners
|
||||
if (arr && arr.length > 0) {
|
||||
this.scanners = arr.filter(scanner => {
|
||||
return !scanner.disabled;
|
||||
});
|
||||
}
|
||||
} else { // get all the scanners in specified times
|
||||
const times: number = Math.ceil(totalCount / DEFAULT_PAGE_SIZE);
|
||||
const observableList: Observable<Project[]>[] = [];
|
||||
for (let i = 2; i <= times; i++) {
|
||||
observableList.push(this.projectService.listScannerCandidatesOfProject({
|
||||
page: i,
|
||||
pageSize: DEFAULT_PAGE_SIZE,
|
||||
projectNameOrId: this.projectId.toString()
|
||||
}));
|
||||
}
|
||||
forkJoin(observableList).subscribe(res => {
|
||||
if (res && res.length) {
|
||||
res.forEach(item => {
|
||||
arr = arr.concat(item);
|
||||
});
|
||||
this.scanners = arr.filter(scanner => {
|
||||
return !scanner.disabled;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
close() {
|
||||
@ -118,8 +153,12 @@ export class ScannerComponent implements OnInit {
|
||||
}
|
||||
save() {
|
||||
this.saveBtnState = ClrLoadingState.LOADING;
|
||||
this.configScannerService.updateProjectScanner(this.projectId, this.selectedScanner.uuid)
|
||||
.subscribe(response => {
|
||||
this.projectService.setScannerOfProject({
|
||||
projectNameOrId: this.projectId.toString(),
|
||||
payload: {
|
||||
uuid: this.selectedScanner.uuid
|
||||
}
|
||||
}).subscribe(response => {
|
||||
this.close();
|
||||
this.msgHandler.showSuccess('Update Success');
|
||||
this.getScanner(true);
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { delUrlParam, isSameArrayValue, isSameObject } from "./utils";
|
||||
import { delUrlParam, getQueryString, getSortingString, isSameArrayValue, isSameObject } from "./utils";
|
||||
import { ClrDatagridStateInterface } from "@clr/angular";
|
||||
|
||||
describe('functions in utils.ts should work', () => {
|
||||
it('function isSameArrayValue() should work', () => {
|
||||
@ -30,4 +31,26 @@ describe('functions in utils.ts should work', () => {
|
||||
expect(delUrlParam('http://test.com', 'param2')).toEqual('http://test.com');
|
||||
expect(delUrlParam('http://test.com?param2', 'param2')).toEqual('http://test.com');
|
||||
});
|
||||
|
||||
it('function getSortingString() should work', () => {
|
||||
expect(getSortingString).toBeTruthy();
|
||||
const state: ClrDatagridStateInterface = {
|
||||
sort: {
|
||||
by: 'name',
|
||||
reverse: true
|
||||
}
|
||||
};
|
||||
expect(getSortingString(state)).toEqual('-name');
|
||||
});
|
||||
|
||||
it('function getQueryString() should work', () => {
|
||||
expect(getQueryString).toBeTruthy();
|
||||
const state: ClrDatagridStateInterface = {
|
||||
filters: [
|
||||
{property: 'name', value: 'test'},
|
||||
{property: 'url', value: 'http://test.com'},
|
||||
]
|
||||
};
|
||||
expect(getQueryString(state)).toEqual(encodeURIComponent('name=~test,url=~http://test.com'));
|
||||
});
|
||||
});
|
||||
|
@ -631,6 +631,10 @@ export function deleteEmptyKey(obj: Object): void {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get sorting string from current state
|
||||
* @param state
|
||||
*/
|
||||
export function getSortingString(state: ClrDatagridStateInterface): string {
|
||||
if (state && state.sort && state.sort.by) {
|
||||
let sortString: string;
|
||||
@ -647,6 +651,32 @@ export function getSortingString(state: ClrDatagridStateInterface): string {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get query string from current state, rules as below:
|
||||
* query string format: q=k=v,k=~v,k=[min~max],k={v1 v2 v3},k=(v1 v2 v3)
|
||||
* exact match: k=v
|
||||
* fuzzy match: k=~v
|
||||
* range: k=[min~max]
|
||||
* or list: k={v1 v2 v3}
|
||||
* and list: k=(v1 v2 v3)
|
||||
* @param state
|
||||
*/
|
||||
export function getQueryString(state: ClrDatagridStateInterface): string {
|
||||
let str: string = '';
|
||||
if (state && state.filters && state.filters.length) {
|
||||
state.filters.forEach(item => {
|
||||
if (str) {
|
||||
str += `,${item.property}=~${item.value}`;
|
||||
} else {
|
||||
str += `${item.property}=~${item.value}`;
|
||||
}
|
||||
});
|
||||
return encodeURIComponent(str);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* if two object are the same
|
||||
* @param a
|
||||
|
Loading…
Reference in New Issue
Block a user