Improve scanner UI

Signed-off-by: sshijun <sshijun@vmware.com>
This commit is contained in:
sshijun 2019-10-18 10:46:24 +08:00
parent ad053fc017
commit b406611a3d
23 changed files with 115 additions and 68 deletions

View File

@ -10,7 +10,7 @@
<clr-tab> <clr-tab>
<button id="config-vulnerability" clrTabLink>{{'CONFIG.VULNERABILITY' | translate}}</button> <button id="config-vulnerability" clrTabLink>{{'CONFIG.VULNERABILITY' | translate}}</button>
<clr-tab-content id="vulnerability" *clrIfActive> <clr-tab-content id="vulnerability" *clrIfActive>
<vulnerability-config *ngIf="withClair" #vulnerabilityConfig [showSubTitle]="true"></vulnerability-config> <vulnerability-config #vulnerabilityConfig [showSubTitle]="true"></vulnerability-config>
</clr-tab-content> </clr-tab-content>
</clr-tab> </clr-tab>
<clr-tab> <clr-tab>

View File

@ -19,3 +19,6 @@
.replication-tooltip { .replication-tooltip {
top: -8px; top: -8px;
} }
.margin-top-3px {
margin-top: 3px;
}

View File

@ -73,7 +73,7 @@
</clr-checkbox-container> </clr-checkbox-container>
<div class="clr-form-control d-f" *ngIf="withClair"> <div class="clr-form-control d-f">
<label for="systemWhitelist" <label for="systemWhitelist"
class="clr-control-label">{{'CVE_WHITELIST.DEPLOYMENT_SECURITY'|translate}}</label> class="clr-control-label">{{'CVE_WHITELIST.DEPLOYMENT_SECURITY'|translate}}</label>
<div class="form-content"> <div class="form-content">

View File

@ -10,7 +10,7 @@
<clr-control-helper class="config-subtext"> {{ 'PROJECT_CONFIG.PUBLIC_POLICY' | translate }} <clr-control-helper class="config-subtext"> {{ 'PROJECT_CONFIG.PUBLIC_POLICY' | translate }}
</clr-control-helper> </clr-control-helper>
</clr-checkbox-container> </clr-checkbox-container>
<clr-checkbox-container *ngIf="withNotary || withClair"> <clr-checkbox-container *ngIf="withNotary">
<label><span *ngIf="withNotary">{{ 'PROJECT_CONFIG.SECURITY' | translate }}</span></label> <label><span *ngIf="withNotary">{{ 'PROJECT_CONFIG.SECURITY' | translate }}</span></label>
<clr-checkbox-wrapper *ngIf="withNotary"> <clr-checkbox-wrapper *ngIf="withNotary">
<input type="checkbox" clrCheckbox [(ngModel)]="projectPolicy.ContentTrust" name="content-trust" <input type="checkbox" clrCheckbox [(ngModel)]="projectPolicy.ContentTrust" name="content-trust"
@ -20,9 +20,9 @@
<clr-control-helper class="config-subtext"> {{ 'PROJECT_CONFIG.CONTENT_TRUST_POLCIY' | translate }} <clr-control-helper class="config-subtext"> {{ 'PROJECT_CONFIG.CONTENT_TRUST_POLCIY' | translate }}
</clr-control-helper> </clr-control-helper>
</clr-checkbox-container> </clr-checkbox-container>
<clr-checkbox-container id="prevent-vulenrability-image" *ngIf="withNotary || withClair"> <clr-checkbox-container id="prevent-vulenrability-image" *ngIf="withNotary">
<label><span *ngIf="!withNotary">{{ 'PROJECT_CONFIG.SECURITY' | translate }}</span></label> <label><span *ngIf="!withNotary">{{ 'PROJECT_CONFIG.SECURITY' | translate }}</span></label>
<clr-checkbox-wrapper *ngIf="withClair"> <clr-checkbox-wrapper>
<input type="checkbox" clrCheckbox [(ngModel)]="projectPolicy.PreventVulImg" <input type="checkbox" clrCheckbox [(ngModel)]="projectPolicy.PreventVulImg"
name="prevent-vulenrability-image-input" [disabled]="!hasChangeConfigRole" /> name="prevent-vulenrability-image-input" [disabled]="!hasChangeConfigRole" />
<label>{{ 'PROJECT_CONFIG.PREVENT_VULNERABLE_TOGGLE' | translate }}</label> <label>{{ 'PROJECT_CONFIG.PREVENT_VULNERABLE_TOGGLE' | translate }}</label>
@ -46,7 +46,7 @@
</div> </div>
</clr-control-helper> </clr-control-helper>
</clr-checkbox-container> </clr-checkbox-container>
<clr-checkbox-container *ngIf="withClair"> <clr-checkbox-container>
<label>{{ 'PROJECT_CONFIG.SCAN' | translate }}</label> <label>{{ 'PROJECT_CONFIG.SCAN' | translate }}</label>
<clr-checkbox-wrapper id="scan-image-on-push-wrapper"> <clr-checkbox-wrapper id="scan-image-on-push-wrapper">
<input type="checkbox" clrCheckbox [(ngModel)]="projectPolicy.ScanImgOnPush" <input type="checkbox" clrCheckbox [(ngModel)]="projectPolicy.ScanImgOnPush"
@ -56,7 +56,7 @@
<clr-control-helper class="config-subtext"> {{ 'PROJECT_CONFIG.AUTOSCAN_POLICY' | translate }} <clr-control-helper class="config-subtext"> {{ 'PROJECT_CONFIG.AUTOSCAN_POLICY' | translate }}
</clr-control-helper> </clr-control-helper>
</clr-checkbox-container> </clr-checkbox-container>
<div class="clr-form-control" [class.clr-form-control-disabled]="!hasChangeConfigRole" *ngIf="withClair"> <div class="clr-form-control" [class.clr-form-control-disabled]="!hasChangeConfigRole">
<label for="systemWhitelist" class="clr-control-label">{{'CVE_WHITELIST.CVE_WHITELIST'|translate}}</label> <label for="systemWhitelist" class="clr-control-label">{{'CVE_WHITELIST.CVE_WHITELIST'|translate}}</label>
<div class="w-100 clr-control-container"> <div class="w-100 clr-control-container">
<div class="config-subtext"> <div class="config-subtext">

View File

@ -55,8 +55,7 @@
<section id="image" role="tabpanel" aria-labelledby="repo-image" [hidden]='!isCurrentTabContent("image")'> <section id="image" role="tabpanel" aria-labelledby="repo-image" [hidden]='!isCurrentTabContent("image")'>
<div id=images-container> <div id=images-container>
<hbr-tag ngProjectAs="clr-dg-row-detail" (tagClickEvent)="watchTagClickEvt($event)" (signatureOutput)="saveSignatures($event)" <hbr-tag ngProjectAs="clr-dg-row-detail" (tagClickEvent)="watchTagClickEvt($event)" (signatureOutput)="saveSignatures($event)"
class="sub-grid-custom" [repoName]="repoName" [registryUrl]="registryUrl" [withNotary]="withNotary" class="sub-grid-custom" [repoName]="repoName" [registryUrl]="registryUrl" [withNotary]="withNotary" [withAdmiral]="withAdmiral" [hasSignedIn]="hasSignedIn"
[withClair]="withClair" [withAdmiral]="withAdmiral" [hasSignedIn]="hasSignedIn"
[isGuest]="isGuest" [projectId]="projectId" [memberRoleID]="memberRoleID"></hbr-tag> [isGuest]="isGuest" [projectId]="projectId" [memberRoleID]="memberRoleID"></hbr-tag>
</div> </div>
</section> </section>

View File

@ -85,7 +85,7 @@
<clr-dg-column *ngIf="withNotary">{{'REPOSITORY.SIGNED' | translate}}</clr-dg-column> <clr-dg-column *ngIf="withNotary">{{'REPOSITORY.SIGNED' | translate}}</clr-dg-column>
<clr-dg-column>{{'REPOSITORY.AUTHOR' | translate}}</clr-dg-column> <clr-dg-column>{{'REPOSITORY.AUTHOR' | translate}}</clr-dg-column>
<clr-dg-column [clrDgSortBy]="createdComparator">{{'REPOSITORY.CREATED' | translate}}</clr-dg-column> <clr-dg-column [clrDgSortBy]="createdComparator">{{'REPOSITORY.CREATED' | translate}}</clr-dg-column>
<clr-dg-column [clrDgField]="'docker_version'" *ngIf="!withClair">{{'REPOSITORY.DOCKER_VERSION' | translate}}</clr-dg-column> <clr-dg-column [clrDgField]="'docker_version'">{{'REPOSITORY.DOCKER_VERSION' | translate}}</clr-dg-column>
<clr-dg-column *ngIf="!withAdmiral">{{'REPOSITORY.LABELS' | translate}}</clr-dg-column> <clr-dg-column *ngIf="!withAdmiral">{{'REPOSITORY.LABELS' | translate}}</clr-dg-column>
<clr-dg-column [clrDgSortBy]="pushComparator">{{'REPOSITORY.PUSH_TIME' | translate}}</clr-dg-column> <clr-dg-column [clrDgSortBy]="pushComparator">{{'REPOSITORY.PUSH_TIME' | translate}}</clr-dg-column>
<clr-dg-column [clrDgSortBy]="pullComparator">{{'REPOSITORY.PULL_TIME' | translate}}</clr-dg-column> <clr-dg-column [clrDgSortBy]="pullComparator">{{'REPOSITORY.PULL_TIME' | translate}}</clr-dg-column>
@ -111,7 +111,7 @@
</clr-dg-cell> </clr-dg-cell>
<clr-dg-cell class="truncated" title="{{t.author}}">{{t.author}}</clr-dg-cell> <clr-dg-cell class="truncated" title="{{t.author}}">{{t.author}}</clr-dg-cell>
<clr-dg-cell>{{t.created | date: 'short'}}</clr-dg-cell> <clr-dg-cell>{{t.created | date: 'short'}}</clr-dg-cell>
<clr-dg-cell *ngIf="!withClair">{{t.docker_version}}</clr-dg-cell> <clr-dg-cell>{{t.docker_version}}</clr-dg-cell>
<clr-dg-cell *ngIf="!withAdmiral"> <clr-dg-cell *ngIf="!withAdmiral">
<hbr-label-piece *ngIf="t.labels?.length" [label]="t.labels[0]" [labelWidth]="90"> </hbr-label-piece> <hbr-label-piece *ngIf="t.labels?.length" [label]="t.labels[0]" [labelWidth]="90"> </hbr-label-piece>
<div class="signpost-item" [hidden]="t.labels?.length<=1"> <div class="signpost-item" [hidden]="t.labels?.length<=1">

View File

@ -723,9 +723,7 @@ export class TagComponent implements OnInit, AfterViewInit {
canScanNow(t: Tag[]): boolean { canScanNow(t: Tag[]): boolean {
if (!this.hasScanImagePermission) { return false; } if (!this.hasScanImagePermission) { return false; }
let st: string = this.scanStatus(t[0]); let st: string = this.scanStatus(t[0]);
return st !== VULNERABILITY_SCAN_STATUS.RUNNING;
return st !== VULNERABILITY_SCAN_STATUS.PENDING &&
st !== VULNERABILITY_SCAN_STATUS.RUNNING;
} }
getImagePermissionRule(projectId: number): void { getImagePermissionRule(projectId: number): void {
let hasAddLabelImagePermission = this.userPermissionService.getPermission(projectId, USERSTATICPERMISSION.REPOSITORY_TAG_LABEL.KEY, let hasAddLabelImagePermission = this.userPermissionService.getPermission(projectId, USERSTATICPERMISSION.REPOSITORY_TAG_LABEL.KEY,

View File

@ -43,12 +43,12 @@
</a> </a>
</clr-vertical-nav-group-children> </clr-vertical-nav-group-children>
</clr-vertical-nav-group> </clr-vertical-nav-group>
<clr-vertical-nav-group *ngIf="isSystemAdmin && (withClair || hasAdminRole)" routerLinkActive="active"> <clr-vertical-nav-group *ngIf="isSystemAdmin && hasAdminRole" routerLinkActive="active">
<clr-icon shape="event" clrVerticalNavIcon></clr-icon> <clr-icon shape="event" clrVerticalNavIcon></clr-icon>
{{'SIDE_NAV.TASKS' | translate}} {{'SIDE_NAV.TASKS' | translate}}
<a routerLink="#" hidden aria-hidden="true"></a> <a routerLink="#" hidden aria-hidden="true"></a>
<clr-vertical-nav-group-children *clrIfExpanded="true"> <clr-vertical-nav-group-children *clrIfExpanded="true">
<a clrVerticalNavLink *ngIf="withClair" routerLink="/harbor/vulnerability" <a clrVerticalNavLink routerLink="/harbor/vulnerability"
routerLinkActive="active"> routerLinkActive="active">
{{'SIDE_NAV.SYSTEM_MGMT.VULNERABILITY' | translate}} {{'SIDE_NAV.SYSTEM_MGMT.VULNERABILITY' | translate}}
</a> </a>

View File

@ -17,18 +17,26 @@
<button clrDropdownItem <button clrDropdownItem
(click)="changeStat()" (click)="changeStat()"
[disabled]="!(selectedRow && !selectedRow.is_default)"> [disabled]="!(selectedRow && !selectedRow.is_default)">
<span *ngIf="selectedRow && selectedRow.disabled">{{'BUTTON.ENABLE' | translate}}</span> <span *ngIf="selectedRow && selectedRow.disabled">
<span *ngIf="!(selectedRow && selectedRow.disabled)">{{'BUTTON.DISABLE' | translate}}</span> <clr-icon class="margin-top-2" size="16" shape="success-standard"></clr-icon>
<span class="margin-left-10">{{'SCANNER.ENABLE' | translate}}</span>
</span>
<span *ngIf="!(selectedRow && selectedRow.disabled)">
<clr-icon class="margin-top-2" size="16" shape="ban"></clr-icon>
<span class="margin-left-10">{{'SCANNER.DISABLE' | translate}}</span>
</span>
</button> </button>
<button clrDropdownItem <button clrDropdownItem
(click)="editScanner()" (click)="editScanner()"
class="btn btn-sm btn-secondary" [disabled]="!selectedRow"> class="btn btn-sm btn-secondary" [disabled]="!selectedRow">
{{'BUTTON.EDIT' | translate}} <clr-icon class="margin-top-0" size="16" shape="pencil"></clr-icon>
<span class="margin-left-10">{{'BUTTON.EDIT' | translate}}</span>
</button> </button>
<button clrDropdownItem <button clrDropdownItem
(click)="deleteScanners()" (click)="deleteScanners()"
class="btn btn-sm btn-secondary" [disabled]="!selectedRow"> class="btn btn-sm btn-secondary" [disabled]="!selectedRow">
{{'BUTTON.DELETE' | translate}} <clr-icon class="margin-top-0" size="16" shape="times"></clr-icon>
<span class="margin-left-10">{{'BUTTON.DELETE' | translate}}</span>
</button> </button>
</clr-dropdown-menu> </clr-dropdown-menu>
</clr-dropdown> </clr-dropdown>
@ -45,7 +53,7 @@
<clr-dg-column class="width-240" [clrDgField]="'name'">{{'SCANNER.NAME' | translate}}</clr-dg-column> <clr-dg-column class="width-240" [clrDgField]="'name'">{{'SCANNER.NAME' | translate}}</clr-dg-column>
<clr-dg-column class="width-240" [clrDgField]="'url'">{{'SCANNER.ENDPOINT' | translate}}</clr-dg-column> <clr-dg-column class="width-240" [clrDgField]="'url'">{{'SCANNER.ENDPOINT' | translate}}</clr-dg-column>
<clr-dg-column>{{'SCANNER.HEALTH' | translate}}</clr-dg-column> <clr-dg-column>{{'SCANNER.HEALTH' | translate}}</clr-dg-column>
<clr-dg-column>{{'SCANNER.DISABLED' | translate}}</clr-dg-column> <clr-dg-column>{{'SCANNER.ENABLED' | translate}}</clr-dg-column>
<clr-dg-column>{{'SCANNER.AUTH' | translate}}</clr-dg-column> <clr-dg-column>{{'SCANNER.AUTH' | translate}}</clr-dg-column>
<clr-dg-placeholder> <clr-dg-placeholder>
{{'SCANNER.NO_SCANNER' | translate}} {{'SCANNER.NO_SCANNER' | translate}}
@ -62,7 +70,7 @@
<span class="label label-danger">{{'SCANNER.UNHEALTHY' | translate}}</span> <span class="label label-danger">{{'SCANNER.UNHEALTHY' | translate}}</span>
</ng-template> </ng-template>
</clr-dg-cell> </clr-dg-cell>
<clr-dg-cell>{{scanner.disabled}}</clr-dg-cell> <clr-dg-cell>{{!scanner.disabled}}</clr-dg-cell>
<clr-dg-cell>{{scanner.auth?scanner.auth:'None'}}</clr-dg-cell> <clr-dg-cell>{{scanner.auth?scanner.auth:'None'}}</clr-dg-cell>
<scanner-metadata *clrIfExpanded [uid]="scanner.uuid" ngProjectAs="clr-dg-row-detail"></scanner-metadata> <scanner-metadata *clrIfExpanded [uid]="scanner.uuid" ngProjectAs="clr-dg-row-detail"></scanner-metadata>
</clr-dg-row> </clr-dg-row>

View File

@ -22,3 +22,12 @@
.width-240 { .width-240 {
min-width: 240px !important; min-width: 240px !important;
} }
.margin-top-0 {
margin-top: 0;
}
.margin-top-2 {
margin-top: 2px;
}
.margin-left-10 {
margin-left: 10px;
}

View File

@ -35,7 +35,7 @@ export class ConfigurationScannerComponent implements OnInit, OnDestroy {
confirmed.state === ConfirmationState.CONFIRMED) { confirmed.state === ConfirmationState.CONFIRMED) {
this.configScannerService.deleteScanners(confirmed.data) this.configScannerService.deleteScanners(confirmed.data)
.subscribe(response => { .subscribe(response => {
this.msgHandler.showSuccess("Delete Success"); this.msgHandler.showSuccess("SCANNER.DELETE_SUCCESS");
this.getScanners(); this.getScanners();
}, error => { }, error => {
this.errorHandler.error(error); this.errorHandler.error(error);
@ -76,7 +76,7 @@ export class ConfigurationScannerComponent implements OnInit, OnDestroy {
scanner.disabled = !scanner.disabled; scanner.disabled = !scanner.disabled;
this.configScannerService.updateScanner(scanner) this.configScannerService.updateScanner(scanner)
.subscribe(response => { .subscribe(response => {
this.msgHandler.showSuccess("Update Success"); this.msgHandler.showSuccess("SCANNER.UPDATE_SUCCESS");
this.getScanners(); this.getScanners();
}, error => { }, error => {
this.errorHandler.error(error); this.errorHandler.error(error);
@ -87,7 +87,7 @@ export class ConfigurationScannerComponent implements OnInit, OnDestroy {
if (this.selectedRow) { if (this.selectedRow) {
this.configScannerService.setAsDefault(this.selectedRow.uuid) this.configScannerService.setAsDefault(this.selectedRow.uuid)
.subscribe(response => { .subscribe(response => {
this.msgHandler.showSuccess("Update Success"); this.msgHandler.showSuccess("SCANNER.UPDATE_SUCCESS");
this.getScanners(); this.getScanners();
}, error => { }, error => {
this.errorHandler.error(error); this.errorHandler.error(error);

View File

@ -4,7 +4,7 @@
<label class="required clr-control-label">{{"SCANNER.NAME" | translate}}</label> <label class="required clr-control-label">{{"SCANNER.NAME" | translate}}</label>
<div class="clr-control-container" [class.clr-error]="!isNameValid"> <div class="clr-control-container" [class.clr-error]="!isNameValid">
<div class="clr-input-wrapper"> <div class="clr-input-wrapper">
<input autocomplete="off" #name formControlName="name" class="clr-input width-312" <input autocomplete="off" #name formControlName="name" class="clr-input width-280"
type="text" type="text"
id="scanner-name"> id="scanner-name">
<clr-icon class="clr-validate-icon" shape="exclamation-circle"></clr-icon> <clr-icon class="clr-validate-icon" shape="exclamation-circle"></clr-icon>
@ -18,7 +18,7 @@
<div class="clr-form-control"> <div class="clr-form-control">
<label class="clr-control-label">{{"SCANNER.DESCRIPTION" | translate}}</label> <label class="clr-control-label">{{"SCANNER.DESCRIPTION" | translate}}</label>
<div class="clr-control-container"> <div class="clr-control-container">
<textarea autocomplete="off" formControlName="description" class="clr-textarea width-312" type="text" <textarea autocomplete="off" formControlName="description" class="clr-textarea width-280" type="text"
id="description"> id="description">
</textarea> </textarea>
</div> </div>
@ -28,7 +28,7 @@
<div class="clr-control-container" [class.clr-error]="!isEndpointValid || showEndpointError"> <div class="clr-control-container" [class.clr-error]="!isEndpointValid || showEndpointError">
<div class="clr-input-wrapper"> <div class="clr-input-wrapper">
<input (focus)="showEndpointError=false" (blur)="checkEndpointUrl()" #endpointUrl placeholder="http(s)://192.168.1.1" autocomplete="off" formControlName="url" <input (focus)="showEndpointError=false" (blur)="checkEndpointUrl()" #endpointUrl placeholder="http(s)://192.168.1.1" autocomplete="off" formControlName="url"
class="clr-input width-312" type="text" id="scanner-endpoint"> class="clr-input width-280" type="text" id="scanner-endpoint">
<clr-icon class="clr-validate-icon" shape="exclamation-circle"></clr-icon> <clr-icon class="clr-validate-icon" shape="exclamation-circle"></clr-icon>
<span class="spinner spinner-inline" [hidden]="!checkEndpointOnGoing"></span> <span class="spinner spinner-inline" [hidden]="!checkEndpointOnGoing"></span>
</div> </div>
@ -41,7 +41,7 @@
<label class="clr-control-label">{{"SCANNER.AUTH" | translate}}</label> <label class="clr-control-label">{{"SCANNER.AUTH" | translate}}</label>
<div class="clr-control-container"> <div class="clr-control-container">
<div class="clr-select-wrapper"> <div class="clr-select-wrapper">
<select formControlName="auth" class="clr-select width-312" id="scanner-authorization"> <select formControlName="auth" class="clr-select width-280" id="scanner-authorization">
<option value="None">{{"SCANNER.NONE" | translate}}</option> <option value="None">{{"SCANNER.NONE" | translate}}</option>
<option value="Basic">{{"SCANNER.BASIC" | translate}}</option> <option value="Basic">{{"SCANNER.BASIC" | translate}}</option>
<option value="Bearer">{{"SCANNER.BEARER" | translate}}</option> <option value="Bearer">{{"SCANNER.BEARER" | translate}}</option>
@ -56,7 +56,7 @@
<div class="clr-control-container" [class.clr-error]="!isUserNameValid"> <div class="clr-control-container" [class.clr-error]="!isUserNameValid">
<div class="clr-input-wrapper"> <div class="clr-input-wrapper">
<input formControlName="username" autocomplete="off" <input formControlName="username" autocomplete="off"
class="clr-input width-312" type="text" id="scanner-username"> class="clr-input width-280" type="text" id="scanner-username">
<clr-icon class="clr-validate-icon" shape="exclamation-circle"></clr-icon> <clr-icon class="clr-validate-icon" shape="exclamation-circle"></clr-icon>
</div> </div>
<clr-control-error *ngIf="!isUserNameValid"> <clr-control-error *ngIf="!isUserNameValid">
@ -69,7 +69,7 @@
<div class="clr-control-container" [class.clr-error]="!isPasswordValid"> <div class="clr-control-container" [class.clr-error]="!isPasswordValid">
<div class="clr-input-wrapper"> <div class="clr-input-wrapper">
<input formControlName="password" autocomplete="off" <input formControlName="password" autocomplete="off"
class="clr-input width-312" type="password" id="scanner-password"> class="clr-input width-280" type="password" id="scanner-password">
<clr-icon class="clr-validate-icon" shape="exclamation-circle"></clr-icon> <clr-icon class="clr-validate-icon" shape="exclamation-circle"></clr-icon>
</div> </div>
<clr-control-error *ngIf="!isPasswordValid"> <clr-control-error *ngIf="!isPasswordValid">
@ -82,7 +82,7 @@
<div class="clr-control-container" [class.clr-error]="!isTokenValid"> <div class="clr-control-container" [class.clr-error]="!isTokenValid">
<div class="clr-input-wrapper"> <div class="clr-input-wrapper">
<input formControlName="token" autocomplete="off" <input formControlName="token" autocomplete="off"
class="clr-input width-312" type="text" id="scanner-token"> class="clr-input width-280" type="text" id="scanner-token">
<clr-icon class="clr-validate-icon" shape="exclamation-circle"></clr-icon> <clr-icon class="clr-validate-icon" shape="exclamation-circle"></clr-icon>
</div> </div>
<clr-control-error *ngIf="!isTokenValid"> <clr-control-error *ngIf="!isTokenValid">
@ -95,7 +95,7 @@
<div class="clr-control-container" [class.clr-error]="!isApiKeyValid"> <div class="clr-control-container" [class.clr-error]="!isApiKeyValid">
<div class="clr-input-wrapper"> <div class="clr-input-wrapper">
<input formControlName="apiKey" autocomplete="off" <input formControlName="apiKey" autocomplete="off"
class="clr-input width-312" type="text" id="scanner-apiKey"> class="clr-input width-280" type="text" id="scanner-apiKey">
<clr-icon class="clr-validate-icon" shape="exclamation-circle"></clr-icon> <clr-icon class="clr-validate-icon" shape="exclamation-circle"></clr-icon>
</div> </div>
<clr-control-error *ngIf="!isApiKeyValid"> <clr-control-error *ngIf="!isApiKeyValid">

View File

@ -1,6 +1,9 @@
.width-312 { .width-280 {
width: 312px; width: 280px;
} }
.padding-top-3 { .padding-top-3 {
padding-top: 3px; padding-top: 3px;
} }
.clr-control-label {
width: 9rem !important;
}

View File

@ -21,7 +21,7 @@ export class NewScannerFormComponent implements OnInit, AfterViewInit, OnDestro
checkOnGoing: boolean = false; checkOnGoing: boolean = false;
newScannerForm: FormGroup = this.fb.group({ newScannerForm: FormGroup = this.fb.group({
name: this.fb.control("", name: this.fb.control("",
[Validators.required, Validators.pattern(/^[a-z0-9]+(?:[._-][a-z0-9]+)*$/)]), [Validators.required]),
description: this.fb.control(""), description: this.fb.control(""),
url: this.fb.control("", url: this.fb.control("",
[Validators.required, [Validators.required,
@ -57,7 +57,7 @@ export class NewScannerFormComponent implements OnInit, AfterViewInit, OnDestro
if (this.isEdit && this.originValue && this.originValue.name === name) { if (this.isEdit && this.originValue && this.originValue.name === name) {
return false; return false;
} }
return this.newScannerForm.get('name').valid && name.length > 1; return this.newScannerForm.get('name').valid && name.length > 0;
}), }),
debounceTime(500), debounceTime(500),
distinctUntilChanged(), distinctUntilChanged(),
@ -130,15 +130,15 @@ export class NewScannerFormComponent implements OnInit, AfterViewInit, OnDestro
return true; return true;
} }
if (this.isNameExisting) { if (this.isNameExisting) {
this.nameTooltip = 'NAME_EXISTS'; this.nameTooltip = 'SCANNER.NAME_EXISTS';
return false; return false;
} }
if (this.newScannerForm.get('name').errors && this.newScannerForm.get('name').errors.required) { if (this.newScannerForm.get('name').errors && this.newScannerForm.get('name').errors.required) {
this.nameTooltip = 'NAME_REQUIRED'; this.nameTooltip = 'SCANNER.NAME_REQUIRED';
return false; return false;
} }
if (this.newScannerForm.get('name').errors && this.newScannerForm.get('name').errors.pattern) { if (this.newScannerForm.get('name').errors && this.newScannerForm.get('name').errors.pattern) {
this.nameTooltip = 'NAME_REX'; this.nameTooltip = 'SCANNER.NAME_REX';
return false; return false;
} }
return true; return true;
@ -151,11 +151,11 @@ export class NewScannerFormComponent implements OnInit, AfterViewInit, OnDestro
return true; return true;
} }
if (this.isEndpointUrlExisting) { if (this.isEndpointUrlExisting) {
this.endpointTooltip = 'ENDPOINT_EXISTS'; this.endpointTooltip = 'SCANNER.ENDPOINT_EXISTS';
return false; return false;
} }
if (this.newScannerForm.get('url').errors && this.newScannerForm.get('url').errors.required) { if (this.newScannerForm.get('url').errors && this.newScannerForm.get('url').errors.required) {
this.endpointTooltip = 'ENDPOINT_REQUIRED'; this.endpointTooltip = 'SCANNER.ENDPOINT_REQUIRED';
return false; return false;
} }
// skip here, validate when onblur // skip here, validate when onblur
@ -167,7 +167,7 @@ export class NewScannerFormComponent implements OnInit, AfterViewInit, OnDestro
// validate endpointUrl when onblur // validate endpointUrl when onblur
checkEndpointUrl() { checkEndpointUrl() {
if (this.newScannerForm.get('url').errors && this.newScannerForm.get('url').errors.pattern) { if (this.newScannerForm.get('url').errors && this.newScannerForm.get('url').errors.pattern) {
this.endpointTooltip = "ILLEGAL_ENDPOINT"; this.endpointTooltip = "SCANNER.ILLEGAL_ENDPOINT";
this.showEndpointError = true; this.showEndpointError = true;
} }
} }

View File

@ -5,7 +5,7 @@
<div class="clr-form-control"> <div class="clr-form-control">
<label class="clr-control-label name">{{'SCANNER.SCANNER' | translate}}</label> <label class="clr-control-label name">{{'SCANNER.SCANNER' | translate}}</label>
<div class="clr-control-container"> <div class="clr-control-container">
<button *ngIf="scanners && scanners.length > 0" id="edit-scanner" class="btn btn-link edit" (click)="open()">{{'SCANNER.EDIT' | translate}}</button>
<label *ngIf="!(scanners && scanners.length > 0)" class="name">{{'SCANNER.NOT_AVAILABLE' | translate}}</label> <label *ngIf="!(scanners && scanners.length > 0)" class="name">{{'SCANNER.NOT_AVAILABLE' | translate}}</label>
</div> </div>
</div> </div>
@ -16,9 +16,10 @@
<div class="clr-input-wrapper"> <div class="clr-input-wrapper">
<div class="clr-input-wrapper"> <div class="clr-input-wrapper">
<span id="scanner-name" class="scanner-name">{{scanner?.name}}</span> <span id="scanner-name" class="scanner-name">{{scanner?.name}}</span>
<button *ngIf="scanners && scanners.length > 0" id="edit-scanner" class="btn btn-primary btn-sm" (click)="open()">{{'SCANNER.EDIT' | translate}}</button>
<span *ngIf="scanner?.disabled" class="label label-warning ml-1">{{'SCANNER.DISABLED' | translate}}</span> <span *ngIf="scanner?.disabled" class="label label-warning ml-1">{{'SCANNER.DISABLED' | translate}}</span>
<span *ngIf="scanner?.health" class="label label-success ml-1">{{'SCANNER.HEALTHY' | translate}}</span> <span *ngIf="scanner?.health" class="label label-success ml-1">{{'SCANNER.HEALTHY' | translate}}</span>
<span *ngIf="!scanner?.health" class="label label-danger ml-1">{{'SCANNER.Unhealthy' | translate}}</span> <span *ngIf="!scanner?.health" class="label label-danger ml-1">{{'SCANNER.UNHEALTHY' | translate}}</span>
</div> </div>
</div> </div>
</div> </div>

View File

@ -18,3 +18,6 @@
justify-content: center; justify-content: center;
align-items: center; align-items: center;
} }
.clr-form-control {
margin-top: 0.75rem !important;
}

View File

@ -6,7 +6,6 @@
</div> </div>
<hbr-tag-detail (backEvt)="goBack($event)" <hbr-tag-detail (backEvt)="goBack($event)"
[tagId]="tagId" [tagId]="tagId"
[withClair]="withClair"
[withAdmiral]="withAdmiral" [withAdmiral]="withAdmiral"
[projectId]="projectId" [projectId]="projectId"
[repositoryId]="repositoryId"></hbr-tag-detail> [repositoryId]="repositoryId"></hbr-tag-detail>

View File

@ -1257,10 +1257,10 @@
"ADD_SCANNER": "Add Scanner", "ADD_SCANNER": "Add Scanner",
"EDIT_SCANNER": "Edit Scanner", "EDIT_SCANNER": "Edit Scanner",
"TEST_CONNECTION": "TEST CONNECTION", "TEST_CONNECTION": "TEST CONNECTION",
"ADD_SUCCESS": "Added successfully", "ADD_SUCCESS": "Successfully added ",
"TEST_PASS": "Test passed", "TEST_PASS": "Test passed",
"TEST_FAILED": "Test failed", "TEST_FAILED": "Test failed",
"UPDATE_SUCCESS": "Updated successfully", "UPDATE_SUCCESS": "Successfully updated",
"SCANNER_COLON": "Scanner:", "SCANNER_COLON": "Scanner:",
"NAME_COLON": "Name:", "NAME_COLON": "Name:",
"VENDOR_COLON": "Vendor:", "VENDOR_COLON": "Vendor:",
@ -1284,6 +1284,10 @@
"ADAPTER": "Adapter", "ADAPTER": "Adapter",
"VENDOR": "Vendor", "VENDOR": "Vendor",
"VERSION": "Version", "VERSION": "Version",
"SELECT_SCANNER": "Select Scanner" "SELECT_SCANNER": "Select Scanner",
"ENABLED": "Enabled",
"ENABLE": "Enable",
"DISABLE": "Disable",
"DELETE_SUCCESS": "Successfully deleted"
} }
} }

View File

@ -1254,10 +1254,10 @@
"ADD_SCANNER": "Add Scanner", "ADD_SCANNER": "Add Scanner",
"EDIT_SCANNER": "Edit Scanner", "EDIT_SCANNER": "Edit Scanner",
"TEST_CONNECTION": "TEST CONNECTION", "TEST_CONNECTION": "TEST CONNECTION",
"ADD_SUCCESS": "Added successfully", "ADD_SUCCESS": "Successfully added ",
"TEST_PASS": "Test passed", "TEST_PASS": "Test passed",
"TEST_FAILED": "Test failed", "TEST_FAILED": "Test failed",
"UPDATE_SUCCESS": "Updated successfully", "UPDATE_SUCCESS": "Successfully updated",
"SCANNER_COLON": "Scanner:", "SCANNER_COLON": "Scanner:",
"NAME_COLON": "Name:", "NAME_COLON": "Name:",
"VENDOR_COLON": "Vendor:", "VENDOR_COLON": "Vendor:",
@ -1281,6 +1281,10 @@
"ADAPTER": "Adapter", "ADAPTER": "Adapter",
"VENDOR": "Vendor", "VENDOR": "Vendor",
"VERSION": "Version", "VERSION": "Version",
"SELECT_SCANNER": "Select Scanner" "SELECT_SCANNER": "Select Scanner",
"ENABLED": "Enabled",
"ENABLE": "Enable",
"DISABLE": "Disable",
"DELETE_SUCCESS": "Successfully deleted"
} }
} }

View File

@ -1226,10 +1226,10 @@
"ADD_SCANNER": "Add Scanner", "ADD_SCANNER": "Add Scanner",
"EDIT_SCANNER": "Edit Scanner", "EDIT_SCANNER": "Edit Scanner",
"TEST_CONNECTION": "TEST CONNECTION", "TEST_CONNECTION": "TEST CONNECTION",
"ADD_SUCCESS": "Added successfully", "ADD_SUCCESS": "Successfully added ",
"TEST_PASS": "Test passed", "TEST_PASS": "Test passed",
"TEST_FAILED": "Test failed", "TEST_FAILED": "Test failed",
"UPDATE_SUCCESS": "Updated successfully", "UPDATE_SUCCESS": "Successfully updated",
"SCANNER_COLON": "Scanner:", "SCANNER_COLON": "Scanner:",
"NAME_COLON": "Name:", "NAME_COLON": "Name:",
"VENDOR_COLON": "Vendor:", "VENDOR_COLON": "Vendor:",
@ -1253,6 +1253,10 @@
"ADAPTER": "Adapter", "ADAPTER": "Adapter",
"VENDOR": "Vendor", "VENDOR": "Vendor",
"VERSION": "Version", "VERSION": "Version",
"SELECT_SCANNER": "Select Scanner" "SELECT_SCANNER": "Select Scanner",
"ENABLED": "Enabled",
"ENABLE": "Enable",
"DISABLE": "Disable",
"DELETE_SUCCESS": "Successfully deleted"
} }
} }

View File

@ -1251,10 +1251,10 @@
"ADD_SCANNER": "Add Scanner", "ADD_SCANNER": "Add Scanner",
"EDIT_SCANNER": "Edit Scanner", "EDIT_SCANNER": "Edit Scanner",
"TEST_CONNECTION": "TEST CONNECTION", "TEST_CONNECTION": "TEST CONNECTION",
"ADD_SUCCESS": "Added successfully", "ADD_SUCCESS": "Successfully added ",
"TEST_PASS": "Test passed", "TEST_PASS": "Test passed",
"TEST_FAILED": "Test failed", "TEST_FAILED": "Test failed",
"UPDATE_SUCCESS": "Updated successfully", "UPDATE_SUCCESS": "Successfully updated",
"SCANNER_COLON": "Scanner:", "SCANNER_COLON": "Scanner:",
"NAME_COLON": "Name:", "NAME_COLON": "Name:",
"VENDOR_COLON": "Vendor:", "VENDOR_COLON": "Vendor:",
@ -1278,7 +1278,11 @@
"ADAPTER": "Adapter", "ADAPTER": "Adapter",
"VENDOR": "Vendor", "VENDOR": "Vendor",
"VERSION": "Version", "VERSION": "Version",
"SELECT_SCANNER": "Select Scanner" "SELECT_SCANNER": "Select Scanner",
"ENABLED": "Enabled",
"ENABLE": "Enable",
"DISABLE": "Disable",
"DELETE_SUCCESS": "Successfully deleted"
} }
} }

View File

@ -1256,10 +1256,10 @@
"ADD_SCANNER": "Add Scanner", "ADD_SCANNER": "Add Scanner",
"EDIT_SCANNER": "Edit Scanner", "EDIT_SCANNER": "Edit Scanner",
"TEST_CONNECTION": "TEST CONNECTION", "TEST_CONNECTION": "TEST CONNECTION",
"ADD_SUCCESS": "Added successfully", "ADD_SUCCESS": "Successfully added ",
"TEST_PASS": "Test passed", "TEST_PASS": "Test passed",
"TEST_FAILED": "Test failed", "TEST_FAILED": "Test failed",
"UPDATE_SUCCESS": "Updated successfully", "UPDATE_SUCCESS": "Successfully updated",
"SCANNER_COLON": "Scanner:", "SCANNER_COLON": "Scanner:",
"NAME_COLON": "Name:", "NAME_COLON": "Name:",
"VENDOR_COLON": "Vendor:", "VENDOR_COLON": "Vendor:",
@ -1283,6 +1283,10 @@
"ADAPTER": "Adapter", "ADAPTER": "Adapter",
"VENDOR": "Vendor", "VENDOR": "Vendor",
"VERSION": "Version", "VERSION": "Version",
"SELECT_SCANNER": "Select Scanner" "SELECT_SCANNER": "Select Scanner",
"ENABLED": "Enabled",
"ENABLE": "Enable",
"DISABLE": "Disable",
"DELETE_SUCCESS": "Successfully deleted"
} }
} }

View File

@ -1280,6 +1280,10 @@
"ADAPTER": "适配器", "ADAPTER": "适配器",
"VENDOR": "供应商", "VENDOR": "供应商",
"VERSION": "版本", "VERSION": "版本",
"SELECT_SCANNER": "选择扫描器" "SELECT_SCANNER": "选择扫描器",
"ENABLED": "启用",
"ENABLE": "启用",
"DISABLE": "禁用",
"DELETE_SUCCESS": "删除成功"
} }
} }