Merge pull request #3567 from ninjadq/project_level_policy_ui_enhancement

enhancement the presentation of project level policy
This commit is contained in:
Chandler Deng 2017-11-14 02:57:22 -06:00 committed by GitHub
commit ab7627e5c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 138 additions and 37 deletions

View File

@ -1,6 +1,6 @@
{
"name": "harbor-ui",
"version": "0.4.0",
"version": "0.5.0",
"description": "Harbor shared UI components based on Clarity and Angular4",
"scripts": {
"start": "ng serve --host 0.0.0.0 --port 4500 --proxy-config proxy.config.json",

View File

@ -1,6 +1,6 @@
{
"name": "harbor-ui",
"version": "0.4.0",
"version": "0.5.9",
"description": "Harbor shared UI components based on Clarity and Angular4",
"author": "VMware",
"module": "index.js",

View File

@ -11,22 +11,22 @@ export const PROJECT_POLICY_CONFIG_TEMPLATE = `
</div>
</div>
</div>
<div class="form-group">
<div class="form-group" *ngIf="withNotary || withClair">
<label for="projectPolicyForm">{{ 'PROJECT_CONFIG.SECURITY' | translate }}</label>
<div class="form-content">
<div>
<div *ngIf="withNotary">
<clr-checkbox [(ngModel)]="projectPolicy.ContentTrust" name="content-trust"
[clrDisabled]="!hasProjectAdminRole">{{ 'PROJECT_CONFIG.CONTENT_TRUST_TOGGLE' | translate }}</clr-checkbox>
<div class="chk-explain"><label> {{ 'PROJECT_CONFIG.CONTENT_TRUST_POLCIY' | translate }} </label></div>
</div>
<div>
<div *ngIf="withClair">
<clr-checkbox [(ngModel)]="projectPolicy.PreventVulImg" name="prevent-vulenrability-image" [clrDisabled]="!hasProjectAdminRole">{{ 'PROJECT_CONFIG.PREVENT_VULNERABLE_TOGGLE' | translate }}</clr-checkbox>
<div class="chk-explain">
<label>
<div id="severity-blk">
<div>{{ 'PROJECT_CONFIG.PREVENT_VULNERABLE_1' | translate }}</div>
<div class="select">
<select id="severity" name="severity" [(ngModel)]="projectPolicy.PreventVulImgServerity" [disabled]="!projectPolicy.PreventVulImg">
<select id="severity" name="severity" [(ngModel)]="projectPolicy.PreventVulImgSeverity" [disabled]="!projectPolicy.PreventVulImg">
<option *ngFor='let s of severityOptions' [ngValue]="s.severity">{{ s.severityLevel | translate | uppercase }}</option>
</select>
</div>
@ -37,7 +37,7 @@ export const PROJECT_POLICY_CONFIG_TEMPLATE = `
</div>
</div>
</div>
<div class="form-group">
<div class="form-group" *ngIf="withClair">
<label for="projectPolicyForm">{{ 'PROJECT_CONFIG.SCAN' | translate }}</label>
<div class="form-content">
<clr-checkbox [(ngModel)]="projectPolicy.ScanImgOnPush" name="scan-image-on-push" [clrDisabled]="!hasProjectAdminRole">{{ 'PROJECT_CONFIG.AUTOSCAN_TOGGLE' | translate }}</clr-checkbox>

View File

@ -1,3 +1,4 @@
import { SystemInfoService, SystemInfoDefaultService } from './../service/system-info.service';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ErrorHandler } from '../error-handler/error-handler';
import { ConfirmationDialogComponent } from '../confirmation-dialog/confirmation-dialog.component';
@ -5,13 +6,88 @@ import { ProjectPolicyConfigComponent } from './project-policy-config.component'
import { SharedModule } from '../shared/shared.module';
import { ProjectService, ProjectDefaultService} from '../service/project.service';
import { SERVICE_CONFIG, IServiceConfig} from '../service.config';
import { SystemInfo } from '../service/interface';
import { Project } from './project';
describe('ProjectPolicyConfigComponent', () => {
let systemInfoService: SystemInfoService;
let projectPolicyService: ProjectService;
let spySystemInfo: jasmine.Spy;
let spyProjectPolicies: jasmine.Spy;
let mockSystemInfo: SystemInfo[] = [
{
'with_clair': true,
'with_notary': true,
'with_admiral': false,
'admiral_endpoint': 'NA',
'auth_mode': 'db_auth',
'registry_url': '10.112.122.56',
'project_creation_restriction': 'everyone',
'self_registration': true,
'has_ca_root': false,
'harbor_version': 'v1.1.1-rc1-160-g565110d'
},
{
'with_clair': false,
'with_notary': false,
'with_admiral': false,
'admiral_endpoint': 'NA',
'auth_mode': 'db_auth',
'registry_url': '10.112.122.56',
'project_creation_restriction': 'everyone',
'self_registration': true,
'has_ca_root': false,
'harbor_version': 'v1.1.1-rc1-160-g565110d'
}
];
let mockPorjectPolicies: Project[] | any[] = [
{
'project_id': 1,
'owner_id': 1,
'name': 'library',
'creation_time': '2017-11-03T02:37:24Z',
'update_time': '2017-11-03T02:37:24Z',
'deleted': 0,
'owner_name': '',
'togglable': false,
'current_user_role_id': 0,
'repo_count': 0,
'metadata': {
'public': 'true'
}
},
{
'project_id': 2,
'owner_id': 1,
'name': 'test',
'creation_time': '2017-11-03T02:37:24Z',
'update_time': '2017-11-03T02:37:24Z',
'deleted': 0,
'owner_name': '',
'togglable': false,
'current_user_role_id': 0,
'repo_count': 0,
'metadata': {
'auto_scan': 'true',
'enable_content_trust': 'true',
'prevent_vul': 'true',
'public': 'true',
'severity': 'low'
}
}
];
let component: ProjectPolicyConfigComponent;
let fixture: ComponentFixture<ProjectPolicyConfigComponent>;
let config: IServiceConfig = {
projectPolicyEndpoint: '/api/projects/testing/:id/'
projectPolicyEndpoint: '/api/projects/testing',
systemInfoEndpoint: '/api/systeminfo/testing',
};
beforeEach(async(() => {
@ -25,7 +101,8 @@ describe('ProjectPolicyConfigComponent', () => {
providers: [
ErrorHandler,
{ provide: SERVICE_CONFIG, useValue: config },
{ provide: ProjectService, useClass: ProjectDefaultService }
{ provide: ProjectService, useClass: ProjectDefaultService },
{ provide: SystemInfoService, useClass: SystemInfoDefaultService}
]
})
.compileComponents();
@ -36,6 +113,13 @@ describe('ProjectPolicyConfigComponent', () => {
component = fixture.componentInstance;
component.projectId = 1;
component.hasProjectAdminRole = true;
systemInfoService = fixture.debugElement.injector.get(SystemInfoService);
projectPolicyService = fixture.debugElement.injector.get(ProjectService);
spySystemInfo = spyOn(systemInfoService, 'getSystemInfo').and.returnValues(Promise.resolve(mockSystemInfo[0]));
spyProjectPolicies = spyOn(projectPolicyService, 'getProject').and.returnValues(Promise.resolve(mockPorjectPolicies[0]));
fixture.detectChanges();
});

View File

@ -14,19 +14,20 @@ import { ConfirmationAcknowledgement } from '../confirmation-dialog/confirmation
import { TranslateService } from '@ngx-translate/core';
import { Project } from './project';
import {SystemInfo, SystemInfoService} from '../service/index';
export class ProjectPolicy {
Public: boolean;
ContentTrust: boolean;
PreventVulImg: boolean;
PreventVulImgServerity: string;
PreventVulImgSeverity: string;
ScanImgOnPush: boolean;
constructor() {
this.Public = false;
this.ContentTrust = false;
this.PreventVulImg = false;
this.PreventVulImgServerity = 'low';
this.PreventVulImgSeverity = 'low';
this.ScanImgOnPush = false;
}
@ -34,7 +35,7 @@ export class ProjectPolicy {
this.Public = pro.metadata.public === 'true' ? true : false;
this.ContentTrust = pro.metadata.enable_content_trust === 'true' ? true : false;
this.PreventVulImg = pro.metadata.prevent_vul === 'true' ? true : false;
if (pro.metadata.severity) { this.PreventVulImgServerity = pro.metadata.severity; };
if (pro.metadata.severity) { this.PreventVulImgSeverity = pro.metadata.severity; };
this.ScanImgOnPush = pro.metadata.auto_scan === 'true' ? true : false;
};
}
@ -42,7 +43,7 @@ export class ProjectPolicy {
@Component({
selector: 'hbr-project-policy-config',
template: PROJECT_POLICY_CONFIG_TEMPLATE,
styles: [PROJECT_POLICY_CONFIG_STYLE]
styles: [PROJECT_POLICY_CONFIG_STYLE],
})
export class ProjectPolicyConfigComponent implements OnInit {
onGoing = false;
@ -54,6 +55,7 @@ export class ProjectPolicyConfigComponent implements OnInit {
@ViewChild('cfgConfirmationDialog') confirmationDlg: ConfirmationDialogComponent;
systemInfo: SystemInfo;
orgProjectPolicy = new ProjectPolicy();
projectPolicy = new ProjectPolicy();
@ -68,25 +70,41 @@ export class ProjectPolicyConfigComponent implements OnInit {
private errorHandler: ErrorHandler,
private translate: TranslateService,
private projectService: ProjectService,
private systemInfoService: SystemInfoService,
) {}
ngOnInit(): void {
// assert if project id exist
if (!this.projectId) {
this.errorHandler.error('Project ID cannot be unset.');
return;
}
// get system info
toPromise<SystemInfo>(this.systemInfoService.getSystemInfo())
.then(systemInfo => this.systemInfo = systemInfo)
.catch(error => this.errorHandler.error(error));
// retrive project level policy data
this.retrieve();
}
public get withNotary(): boolean {
return this.systemInfo ? this.systemInfo.with_notary : false;
}
public get withClair(): boolean {
return this.systemInfo ? this.systemInfo.with_clair : false;
}
retrieve(state?: State): any {
toPromise<Project>(this.projectService.
getProject(this.projectId))
.then(
response => {
this.orgProjectPolicy.initByProject(response);
this.projectPolicy.initByProject(response);
})
.catch(error => this.errorHandler.error(error));
toPromise<Project>(this.projectService.getProject(this.projectId))
.then(
response => {
this.orgProjectPolicy.initByProject(response);
this.projectPolicy.initByProject(response);
})
.catch(error => this.errorHandler.error(error));
}
updateProjectPolicy(projectId: string|number, pp: ProjectPolicy) {
@ -99,7 +117,7 @@ export class ProjectPolicyConfigComponent implements OnInit {
isValid() {
let flag = false;
if (!this.projectPolicy.PreventVulImg || this.severityOptions.some(x => x.severity === this.projectPolicy.PreventVulImgServerity)) {
if (!this.projectPolicy.PreventVulImg || this.severityOptions.some(x => x.severity === this.projectPolicy.PreventVulImgSeverity)) {
flag = true;
}
return flag;
@ -115,18 +133,18 @@ export class ProjectPolicyConfigComponent implements OnInit {
}
this.onGoing = true;
toPromise<any>(this.projectService.updateProjectPolicy(this.projectId, this.projectPolicy))
.then(() => {
this.onGoing = false;
.then(() => {
this.onGoing = false;
this.translate.get('CONFIG.SAVE_SUCCESS').subscribe((res: string) => {
this.errorHandler.info(res);
});
this.refresh();
})
.catch(error => {
this.onGoing = false;
this.errorHandler.error(error);
this.translate.get('CONFIG.SAVE_SUCCESS').subscribe((res: string) => {
this.errorHandler.info(res);
});
this.refresh();
})
.catch(error => {
this.onGoing = false;
this.errorHandler.error(error);
});
}
cancel(): void {

View File

@ -2,12 +2,11 @@ export class Project {
project_id: number;
owner_id: number;
name: string;
creation_time: Date;
creation_time_str: string;
creation_time: Date | string;
deleted: number;
owner_name: string;
togglable: boolean;
update_time: Date;
update_time: Date | string;
current_user_role_id: number;
repo_count: number;
has_project_admin_role: boolean;

View File

@ -74,7 +74,7 @@ export class ProjectDefaultService extends ProjectService {
'public': projectPolicy.Public ? 'true' : 'false',
'enable_content_trust': projectPolicy.ContentTrust ? 'true' : 'false',
'prevent_vul': projectPolicy.PreventVulImg ? 'true' : 'false',
'severity': projectPolicy.PreventVulImgServerity,
'severity': projectPolicy.PreventVulImgSeverity,
'auto_scan': projectPolicy.ScanImgOnPush ? 'true' : 'false'
} }, HTTP_JSON_OPTIONS)
.map(response => response.status)

View File

@ -31,7 +31,7 @@
"clarity-icons": "^0.9.8",
"clarity-ui": "^0.9.8",
"core-js": "^2.4.1",
"harbor-ui": "0.5.8",
"harbor-ui": "0.5.9",
"intl": "^1.2.5",
"mutationobserver-shim": "^0.3.2",
"ngx-cookie": "^1.0.0",