Improve p2p UI

Signed-off-by: AllForNothing <sshijun@vmware.com>
This commit is contained in:
AllForNothing 2020-07-30 15:23:57 +08:00
parent 5b1b94f25c
commit 7065a7a0a7
16 changed files with 178 additions and 100 deletions

View File

@ -78,12 +78,12 @@
'DISTRIBUTION.NOT_FOUND' | translate
}}</clr-dg-placeholder>
<clr-dg-row *ngFor="let instance of instances" [clrDgItem]="instance">
<clr-dg-cell>
<clr-dg-cell class="no-wrapper">
<span>{{ instance.name }}</span>
<span *ngIf="instance.default" class="label label-info ml-1">{{'SCANNER.DEFAULT' | translate}}</span>
</clr-dg-cell>
<clr-dg-cell>{{ instance.endpoint }}</clr-dg-cell>
<clr-dg-cell>
<clr-dg-cell class="no-wrapper">
<span>{{ instance.vendor }}</span>
<clr-signpost *ngIf="providerMap[instance.vendor]">
<clr-signpost-content *clrIfOpen>

View File

@ -85,47 +85,6 @@
</clr-control-error>
</div>
</div>
<clr-checkbox-container class="margin-top-06" *ngIf="withNotary()">
<label class="width-6rem">{{'P2P_PROVIDER.CRITERIA' | translate}}</label>
<clr-checkbox-wrapper>
<input clrCheckbox type="checkbox" id="onlySignedImages" [(ngModel)]="onlySignedImages" name="onlySignedImages">
<label for="onlySignedImages">{{'P2P_PROVIDER.ONLY_SIGNED' | translate}}</label>
</clr-checkbox-wrapper>
</clr-checkbox-container>
<div class="clr-form-control mt-0" *ngIf="withNotary() && enableContentTrust && !onlySignedImages">
<label for="repo" class="width-6rem"></label>
<div class="clr-control-container">
<label class="label label-warning warning">
<span>{{'P2P_PROVIDER.CONTENT_WARNING' | translate}}</span>
</label>
</div>
</div>
<div class="clr-form-control margin-top-06" [ngClass]="{'mt-1': !withNotary()}">
<label for="repo" class="clr-control-label width-6rem">
<span *ngIf="!withNotary()">{{'P2P_PROVIDER.CRITERIA' | translate}}</span>
</label>
<div class="clr-control-container flex">
<label class="sub-text">{{'P2P_PROVIDER.START_TEXT' | translate}}&nbsp;</label>
<div class="clr-select-wrapper ">
<select id="severity" name="severity" class="clr-select"
#ngSeverity="ngModel"
[(ngModel)]="severity">
<option>--</option>
<option [selected]="severity == s.severity" *ngFor='let s of severityOptions' value="{{s.severity}}">
{{ s.severityLevel | translate }}</option>
</select>
</div>
<label class="sub-text">&nbsp;{{'P2P_PROVIDER.EDN_TEXT' | translate}}</label>
</div>
</div>
<div class="clr-form-control mt-0" *ngIf="compare()">
<label for="repo" class="width-6rem"></label>
<div class="clr-control-container">
<label class="label label-warning warning">
<span>{{'P2P_PROVIDER.SEVERITY_WARNING' | translate}}</span>
</label>
</div>
</div>
<div class="clr-form-control margin-top-06">
<label for="repo" class="clr-control-label width-6rem"></label>
<div class="clr-control-container">
@ -137,19 +96,72 @@
</div>
</div>
</div>
<clr-select-container>
<label class="clr-control-label width-6rem">{{'P2P_PROVIDER.TRIGGER' | translate}}</label>
<select class="width-380" [disabled]="loading"
clrSelect
name="triggerType" id="trigger-type"
#ngTriggerType="ngModel"
[(ngModel)]="triggerType"
>
<option class="display-none" value=""></option>
<option [selected]="triggerType == item" *ngFor="let item of triggers" value="{{item}}">{{getTriggerTypeI18n(item)| translate}}</option>
</select>
</clr-select-container>
<div class="clr-form-control margin-top-06" *ngIf="withNotary() && enableContentTrust">
<label class="clr-control-label width-6rem">
<span>{{'P2P_PROVIDER.CRITERIA' | translate}}</span>
<clr-tooltip>
<clr-icon class="cri-tooltip" clrTooltipTrigger shape="info-circle" size="24"></clr-icon>
<clr-tooltip-content clrPosition="top-left" clrSize="lg" *clrIfOpen>
{{'P2P_PROVIDER.CRITERIA_EXPLAIN' | translate}}
</clr-tooltip-content>
</clr-tooltip>
</label>
<div class="clr-control-container opacity-054">
<div class="clr-checkbox-wrapper">
<input class="clr-checkbox" disabled type="checkbox" id="onlySignedImages" [(ngModel)]="onlySignedImages" name="onlySignedImages">
<label for="onlySignedImages">{{'P2P_PROVIDER.ONLY_SIGNED' | translate}}</label>
</div>
</div>
</div>
<div class="clr-form-control margin-top-06" *ngIf="preventVul" [ngClass]="{'mt-1': !withNotary()}">
<label for="repo" class="clr-control-label width-6rem">
<ng-container *ngIf="!(withNotary() && enableContentTrust)">
<span>{{'P2P_PROVIDER.CRITERIA' | translate}}</span>
<clr-tooltip>
<clr-icon class="tooltip" clrTooltipTrigger shape="info-circle" size="24"></clr-icon>
<clr-tooltip-content clrPosition="top-left" clrSize="lg" *clrIfOpen>
{{'P2P_PROVIDER.CRITERIA_EXPLAIN' | translate}}
</clr-tooltip-content>
</clr-tooltip>
</ng-container>
</label>
<div class="clr-control-container flex">
<label class="sub-text opacity-054">{{'P2P_PROVIDER.START_TEXT' | translate}}&nbsp;</label>
<div class="clr-select-wrapper ">
<select disabled id="severity" name="severity" class="clr-select"
#ngSeverity="ngModel"
[(ngModel)]="severity">
<option>--</option>
<option [selected]="severity == s.severity" *ngFor='let s of severityOptions' value="{{s.severity}}">
{{ s.severityLevel | translate }}</option>
</select>
</div>
<label class="sub-text opacity-054">&nbsp;{{'P2P_PROVIDER.EDN_TEXT' | translate}}</label>
</div>
</div>
<div class="flex baseline">
<clr-select-container>
<label class="clr-control-label width-6rem">{{'P2P_PROVIDER.TRIGGER' | translate}}</label>
<select class="width-380" [disabled]="loading"
clrSelect
name="triggerType" id="trigger-type"
#ngTriggerType="ngModel"
[(ngModel)]="triggerType"
>
<option class="display-none" value=""></option>
<option [selected]="triggerType == item" *ngFor="let item of triggers" value="{{item}}">{{getTriggerTypeI18n(item)| translate}}</option>
</select>
</clr-select-container>
<clr-tooltip *ngIf="showExplainForEventBased()">
<clr-icon clrTooltipTrigger shape="info-circle" size="24"></clr-icon>
<clr-tooltip-content clrPosition="top-right" clrSize="lg" *clrIfOpen>
<div>{{'P2P_PROVIDER.EVENT_BASED_EXPLAIN_LINE1' | translate}}</div>
<div>{{'P2P_PROVIDER.EVENT_BASED_EXPLAIN_LINE2' | translate}}</div>
<div>{{'P2P_PROVIDER.EVENT_BASED_EXPLAIN_LINE3' | translate}}</div>
<div>{{'P2P_PROVIDER.EVENT_BASED_EXPLAIN_LINE4' | translate}}</div>
</clr-tooltip-content>
</clr-tooltip>
</div>
<div class="clr-form-control margin-top-06" *ngIf="showCron()">
<label for="repo" class="clr-control-label width-6rem"></label>
<div class="clr-control-container">

View File

@ -71,3 +71,15 @@
white-space: normal;
height: auto;
}
.cri-tooltip {
margin-top: -2px;
}
.cri-tooltip:focus {
outline: none;
}
.baseline {
align-items: baseline;
}
.opacity-054 {
opacity: 0.54;
}

View File

@ -16,6 +16,7 @@ import { AppConfigService } from '../../../services/app-config.service';
import { InlineAlertComponent } from '../../../shared/inline-alert/inline-alert.component';
import { of } from 'rxjs';
import { delay } from 'rxjs/operators';
import { ProjectService } from '../../../../lib/services';
describe('AddP2pPolicyComponent', () => {
let component: AddP2pPolicyComponent;
let fixture: ComponentFixture<AddP2pPolicyComponent>;
@ -60,6 +61,18 @@ describe('AddP2pPolicyComponent', () => {
};
}
};
const mockedProjectService = {
getProject() {
return of({
name: 'library',
metadata: {
prevent_vul: 'true',
enable_content_trust: 'true',
severity: 'none'
}
});
}
};
beforeEach(async(() => {
TestBed.configureTestingModule({
schemas: [
@ -83,6 +96,7 @@ describe('AddP2pPolicyComponent', () => {
{ provide: ActivatedRoute, useValue: mockActivatedRoute },
{ provide: SessionService, useValue: mockedSessionService },
{ provide: AppConfigService, useValue: mockedAppConfigService },
{ provide: ProjectService, useValue: mockedProjectService },
]
})
.compileComponents();

View File

@ -2,7 +2,7 @@ import { Component, EventEmitter, Input, OnInit, Output, ViewChild, } from '@ang
import { PreheatPolicy } from '../../../../../ng-swagger-gen/models/preheat-policy';
import { InlineAlertComponent } from '../../../shared/inline-alert/inline-alert.component';
import { NgForm } from '@angular/forms';
import { OriginCron } from '../../../../lib/services';
import { OriginCron, ProjectService } from '../../../../lib/services';
import { CronScheduleComponent } from '../../../../lib/components/cron-schedule';
import { PreheatService } from '../../../../../ng-swagger-gen/services/preheat.service';
import { finalize } from 'rxjs/operators';
@ -77,7 +77,8 @@ export class AddP2pPolicyComponent implements OnInit {
constructor(private preheatService: PreheatService,
private session: SessionService,
private route: ActivatedRoute,
private appConfigService: AppConfigService) {
private appConfigService: AppConfigService,
private projectService: ProjectService) {
}
ngOnInit() {
@ -86,27 +87,34 @@ export class AddP2pPolicyComponent implements OnInit {
const project = <Project>(resolverData["projectResolver"]);
this.projectName = project.name;
this.projectId = project.project_id;
if (project && project.metadata) {
this.preventVul = project.metadata.prevent_vul === TRUE;
this.projectSeverity = project.metadata.severity;
this.enableContentTrust = project.metadata.enable_content_trust === TRUE;
}
// get latest project info
this.getProject();
}
}
getProject() {
this.projectService.getProject(this.projectId)
.subscribe(project => {
if (project && project.metadata) {
this.preventVul = project.metadata.prevent_vul === TRUE;
this.projectSeverity = project.metadata.severity;
this.enableContentTrust = project.metadata.enable_content_trust === TRUE;
this.severity = PROJECT_SEVERITY_LEVEL_MAP[this.projectSeverity];
}
});
}
resetForAdd() {
this.currentForm.reset({
triggerType: "manual"
});
this.inlineAlert.close();
this.policy = {};
this.repos = null;
this.tags = null;
this.onlySignedImages = false;
this.severity = null;
this.labels = null;
this.triggerType = "manual";
this.cron = null;
this.currentForm.reset({
triggerType: "manual",
severity: PROJECT_SEVERITY_LEVEL_MAP[this.projectSeverity],
onlySignedImages: this.enableContentTrust
});
}
setCron(event: any) {
@ -161,9 +169,6 @@ export class AddP2pPolicyComponent implements OnInit {
filters.push({type: FILTER_TYPE.TAG, value: this.tags});
}
}
if (this.onlySignedImages) {
filters.push({type: FILTER_TYPE.SIGNATURE, value: this.onlySignedImages});
}
if (this.labels) {
if (this.labels.indexOf(",") !== -1) {
filters.push({type: FILTER_TYPE.LABEL, value: `{${this.labels}}`});
@ -171,9 +176,6 @@ export class AddP2pPolicyComponent implements OnInit {
filters.push({type: FILTER_TYPE.LABEL, value: this.labels});
}
}
if (this.severity === 0 || this.severity > 0) {
filters.push({type: FILTER_TYPE.VULNERABILITY, value: +this.severity});
}
policy.filters = JSON.stringify(filters);
const trigger: any = {
type: this.triggerType ? this.triggerType : TRIGGER.MANUAL,
@ -220,6 +222,9 @@ export class AddP2pPolicyComponent implements OnInit {
}
valid(): boolean {
if (this.triggerType === TRIGGER.SCHEDULED && !this.cron) {
return false;
}
return this.currentForm.valid;
}
@ -293,4 +298,7 @@ export class AddP2pPolicyComponent implements OnInit {
withNotary(): boolean {
return this.appConfigService.getConfig().with_notary;
}
showExplainForEventBased(): boolean {
return this.triggerType === TRIGGER.EVENT_BASED;
}
}

View File

@ -1,5 +1,13 @@
<div class="row">
<h4 class="mt-1">{{'P2P_PROVIDER.POLICIES' | translate}}</h4>
<h4 class="mt-1">
<span>{{'P2P_PROVIDER.POLICIES' | translate}}</span>
<clr-tooltip>
<clr-icon class="color-57" clrTooltipTrigger shape="info-circle" size="24"></clr-icon>
<clr-tooltip-content clrPosition="top-right" clrSize="lg" *clrIfOpen>
{{'P2P_PROVIDER.PREHEAT_EXPLAIN' | translate}}
</clr-tooltip-content>
</clr-tooltip>
</h4>
<clr-datagrid (clrDgSingleSelectedChange)="refreshJobs($event)" [clrDgLoading]="loading" [(clrDgSingleSelected)]="selectedRow">
<clr-dg-action-bar>
<div class="clr-row">
@ -116,7 +124,7 @@
<span>&nbsp;{{'P2P_PROVIDER.EDN_TEXT' | translate}}</span>
</div>
</clr-dg-cell>
<clr-dg-cell>
<clr-dg-cell class="no-wrapper">
{{getTriggerTypeI18n(p.trigger) | translate}}
<clr-signpost *ngIf="isScheduled(p.trigger)">
<clr-signpost-content *clrIfOpen>

View File

@ -44,3 +44,6 @@
.opacity08 {
opacity: 0.8;
}
.no-wrapper {
white-space: nowrap;
}

View File

@ -12,7 +12,7 @@ import { HttpClientTestingModule } from '@angular/common/http/testing';
import { delay } from "rxjs/operators";
import { InlineAlertComponent } from "../../../shared/inline-alert/inline-alert.component";
import { ConfirmationDialogComponent } from "../../../../lib/components/confirmation-dialog";
import { UserPermissionService } from '../../../../lib/services';
import { ProjectService, UserPermissionService } from '../../../../lib/services';
import { PolicyComponent } from './policy.component';
import { PreheatService } from '../../../../../ng-swagger-gen/services/preheat.service';
import { AddP2pPolicyComponent } from '../add-p2p-policy/add-p2p-policy.component';
@ -113,7 +113,18 @@ describe('PolicyComponent', () => {
return of([execution]).pipe(delay(0));
}
};
const mockedProjectService = {
getProject() {
return of({
name: 'library',
metadata: {
prevent_vul: 'true',
enable_content_trust: 'true',
severity: 'none'
}
});
}
};
beforeEach(async(() => {
TestBed.configureTestingModule({
schemas: [
@ -142,6 +153,7 @@ describe('PolicyComponent', () => {
{ provide: UserPermissionService, useValue: mockUserPermissionService },
{ provide: SessionService, useValue: mockedSessionService },
{ provide: AppConfigService, useValue: mockedAppConfigService },
{ provide: ProjectService, useValue: mockedProjectService },
]
})
.compileComponents();

View File

@ -255,6 +255,7 @@ export class PolicyComponent implements OnInit, OnDestroy {
if (this.selectedRow) {
this.addP2pPolicyComponent.isOpen = true;
this.addP2pPolicyComponent.isEdit = true;
this.addP2pPolicyComponent.inlineAlert.close();
this.addP2pPolicyComponent.policy = clone(this.selectedRow);
const filter: any[] = JSON.parse(this.selectedRow.filters);
if (filter && filter.length) {
@ -265,15 +266,9 @@ export class PolicyComponent implements OnInit, OnDestroy {
if (item.type === FILTER_TYPE.TAG && item.value) {
this.addP2pPolicyComponent.tags = item.value.replace(/[{}]/g, "");
}
if (item.type === FILTER_TYPE.SIGNATURE) {
this.addP2pPolicyComponent.onlySignedImages = item.value;
}
if (item.type === FILTER_TYPE.LABEL && item.value) {
this.addP2pPolicyComponent.labels = item.value.replace(/[{}]/g, "");
}
if (item.type === FILTER_TYPE.VULNERABILITY) {
this.addP2pPolicyComponent.severity = item.value;
}
});
}
const trigger: any = JSON.parse(this.selectedRow.trigger);

View File

@ -1502,7 +1502,7 @@
"CREATE_INSTANCE": "Create instance"
},
"P2P_PROVIDER": {
"P2P_PROVIDER": "Preheat",
"P2P_PROVIDER": "P2P Preheat",
"POLICIES": "Policies",
"NEW_POLICY": "NEW POLICY",
"NAME": "Name",
@ -1565,6 +1565,8 @@
"UPDATED_SUCCESSFULLY": "Updated policy successfully",
"EXECUTIONS": "Executions",
"TAG_SEPARATOR": "Enter multiple comma separated tags,tag*,or **",
"CONTENT_WARNING": "Content trust settings here conflicts with the relevant project configuration that will override the settings here"
"CONTENT_WARNING": "Content trust settings here conflicts with the relevant project configuration that will override the settings here",
"PREHEAT_EXPLAIN": "Preheat will migrate the image to the p2p network",
"CRITERIA_EXPLAIN": "As specified in 'Deployment security' section under Configuration tab"
}
}

View File

@ -1500,7 +1500,7 @@
"CREATE_INSTANCE": "Create instance"
},
"P2P_PROVIDER": {
"P2P_PROVIDER": "Preheat",
"P2P_PROVIDER": "P2P Preheat",
"POLICIES": "Policies",
"NEW_POLICY": "NEW POLICY",
"NAME": "Name",
@ -1563,6 +1563,8 @@
"UPDATED_SUCCESSFULLY": "Updated policy successfully",
"EXECUTIONS": "Executions",
"TAG_SEPARATOR": "Enter multiple comma separated tags,tag*,or **",
"CONTENT_WARNING": "Content trust settings here conflicts with the relevant project configuration that will override the settings here"
"CONTENT_WARNING": "Content trust settings here conflicts with the relevant project configuration that will override the settings here",
"PREHEAT_EXPLAIN": "Preheat will migrate the image to the p2p network",
"CRITERIA_EXPLAIN": "As specified in 'Deployment security' section under Configuration tab"
}
}

View File

@ -1470,7 +1470,7 @@
"CREATE_INSTANCE": "Create instance"
},
"P2P_PROVIDER": {
"P2P_PROVIDER": "Preheat",
"P2P_PROVIDER": "P2P Preheat",
"POLICIES": "Policies",
"NEW_POLICY": "NEW POLICY",
"NAME": "Name",
@ -1533,6 +1533,8 @@
"UPDATED_SUCCESSFULLY": "Updated policy successfully",
"EXECUTIONS": "Executions",
"TAG_SEPARATOR": "Enter multiple comma separated tags,tag*,or **",
"CONTENT_WARNING": "Content trust settings here conflicts with the relevant project configuration that will override the settings here"
"CONTENT_WARNING": "Content trust settings here conflicts with the relevant project configuration that will override the settings here",
"PREHEAT_EXPLAIN": "Preheat will migrate the image to the p2p network",
"CRITERIA_EXPLAIN": "As specified in 'Deployment security' section under Configuration tab"
}
}

View File

@ -1498,7 +1498,7 @@
"CREATE_INSTANCE": "Create instance"
},
"P2P_PROVIDER": {
"P2P_PROVIDER": "Preheat",
"P2P_PROVIDER": "P2P Preheat",
"POLICIES": "Policies",
"NEW_POLICY": "NEW POLICY",
"NAME": "Name",
@ -1561,7 +1561,9 @@
"UPDATED_SUCCESSFULLY": "Updated policy successfully",
"EXECUTIONS": "Executions",
"TAG_SEPARATOR": "Enter multiple comma separated tags,tag*,or **",
"CONTENT_WARNING": "Content trust settings here conflicts with the relevant project configuration that will override the settings here"
"CONTENT_WARNING": "Content trust settings here conflicts with the relevant project configuration that will override the settings here",
"PREHEAT_EXPLAIN": "Preheat will migrate the image to the p2p network",
"CRITERIA_EXPLAIN": "As specified in 'Deployment security' section under Configuration tab"
}
}

View File

@ -1502,7 +1502,7 @@
"CREATE_INSTANCE": "Create instance"
},
"P2P_PROVIDER": {
"P2P_PROVIDER": "Preheat",
"P2P_PROVIDER": "P2P Preheat",
"POLICIES": "Policies",
"NEW_POLICY": "NEW POLICY",
"NAME": "Name",
@ -1565,6 +1565,8 @@
"UPDATED_SUCCESSFULLY": "Updated policy successfully",
"EXECUTIONS": "Executions",
"TAG_SEPARATOR": "Enter multiple comma separated tags,tag*,or **",
"CONTENT_WARNING": "Content trust settings here conflicts with the relevant project configuration that will override the settings here"
"CONTENT_WARNING": "Content trust settings here conflicts with the relevant project configuration that will override the settings here",
"PREHEAT_EXPLAIN": "Preheat will migrate the image to the p2p network",
"CRITERIA_EXPLAIN": "As specified in 'Deployment security' section under Configuration tab"
}
}

View File

@ -1356,7 +1356,7 @@
},
"SCANNER": {
"DELETION_SUMMARY": "确定删除扫描器{{param}}",
"SKIP_CERT_VERIFY": "当远程注册使用自签或不可信证书时可勾选此项以跳过证书认证。",
"SKIP_CERT_VERIFY": "当远端服务使用自签或不可信证书时可勾选此项以跳过证书认证。",
"NAME": "名称",
"NAME_EXISTS": "名称已存在",
"NAME_REQUIRED": "名称为必填项",
@ -1499,7 +1499,7 @@
"CREATE_INSTANCE": "新建实例"
},
"P2P_PROVIDER": {
"P2P_PROVIDER": "预热",
"P2P_PROVIDER": "P2P 预热",
"POLICIES": "策略",
"NEW_POLICY": "新建策略",
"NAME": "名称",
@ -1562,6 +1562,8 @@
"UPDATED_SUCCESSFULLY": "更新策略成功",
"EXECUTIONS": "执行记录",
"TAG_SEPARATOR": "使用逗号分割 tags,tag* 和 **",
"CONTENT_WARNING": "内容信任设置与项目设置冲突且将会被项目设置覆盖"
"CONTENT_WARNING": "内容信任设置与项目设置冲突且将会被项目设置覆盖",
"PREHEAT_EXPLAIN": "预热功能可加载镜像至 P2P 网络",
"CRITERIA_EXPLAIN": "由项目设置下的'部署安全'项所指定"
}
}

View File

@ -1486,7 +1486,7 @@
"CREATE_INSTANCE": "Create instance"
},
"P2P_PROVIDER": {
"P2P_PROVIDER": "Preheat",
"P2P_PROVIDER": "P2P Preheat",
"POLICIES": "Policies",
"NEW_POLICY": "NEW POLICY",
"NAME": "Name",
@ -1549,6 +1549,8 @@
"UPDATED_SUCCESSFULLY": "Updated policy successfully",
"EXECUTIONS": "Executions",
"TAG_SEPARATOR": "Enter multiple comma separated tags,tag*,or **",
"CONTENT_WARNING": "Content trust settings here conflicts with the relevant project configuration that will override the settings here"
"CONTENT_WARNING": "Content trust settings here conflicts with the relevant project configuration that will override the settings here",
"PREHEAT_EXPLAIN": "Preheat will migrate the image to the p2p network",
"CRITERIA_EXPLAIN": "As specified in 'Deployment security' section under Configuration tab"
}
}