From 1d543c9212e5e030c116fde4c1006aeba8cacaa9 Mon Sep 17 00:00:00 2001 From: Steven Zou <szou@vmware.com> Date: Tue, 13 Jun 2017 20:38:21 +0800 Subject: [PATCH 1/3] Improve components in UI library --- .../src/endpoint/endpoint.component.css.ts | 9 +++++-- .../src/endpoint/endpoint.component.html.ts | 12 +++++---- src/ui_ng/lib/src/filter/filter.component.ts | 15 +++++++++++ src/ui_ng/lib/src/filter/filter.template.ts | 26 +++++++++++++++++-- .../list-replication-rule.component.html.ts | 9 ++++--- src/ui_ng/lib/src/log/recent-log.component.ts | 8 +++--- src/ui_ng/lib/src/log/recent-log.template.ts | 7 ++--- .../replication/replication.component.css.ts | 11 ++++++-- .../replication/replication.component.html.ts | 18 ++++++------- .../repository-stackview.component.css.ts | 9 ++++--- .../repository-stackview.component.html.ts | 10 ++++--- .../lib/src/tag/tag-detail.component.spec.ts | 4 ++- src/ui_ng/lib/src/utils.ts | 7 ++++- .../result-grid.component.spec.ts | 3 ++- .../result-grid.component.ts | 8 ++++++ .../vulnerability-scanning/scanning.css.ts | 24 +++++++---------- .../vulnerability-scanning/scanning.html.ts | 12 ++++++++- 17 files changed, 137 insertions(+), 55 deletions(-) diff --git a/src/ui_ng/lib/src/endpoint/endpoint.component.css.ts b/src/ui_ng/lib/src/endpoint/endpoint.component.css.ts index 8eab04166..6452b5d9a 100644 --- a/src/ui_ng/lib/src/endpoint/endpoint.component.css.ts +++ b/src/ui_ng/lib/src/endpoint/endpoint.component.css.ts @@ -1,10 +1,15 @@ export const ENDPOINT_STYLE: string = ` .option-left { padding-left: 16px; - margin-top: 24px; + margin-top: -6px; } .option-right { padding-right: 16px; - margin-top: 36px; + } + .refresh-btn { + cursor: pointer; + } + .refresh-btn:hover { + color: #007CBB; } `; \ No newline at end of file diff --git a/src/ui_ng/lib/src/endpoint/endpoint.component.html.ts b/src/ui_ng/lib/src/endpoint/endpoint.component.html.ts index 926d79083..ebd4ce84d 100644 --- a/src/ui_ng/lib/src/endpoint/endpoint.component.html.ts +++ b/src/ui_ng/lib/src/endpoint/endpoint.component.html.ts @@ -1,17 +1,17 @@ export const ENDPOINT_TEMPLATE: string = ` - <confirmation-dialog #confirmationDialog (confirmAction)="confirmDeletion($event)"></confirmation-dialog> +<div> <div class="row"> <div class="col-lg-12 col-md-12 col-sm-12 col-xs-12"> - <div class="row flex-items-xs-between"> + <div class="row flex-items-xs-between" style="height: 24px;"> <div class="flex-items-xs-middle option-left"> <button class="btn btn-link" (click)="openModal()"><clr-icon shape="add"></clr-icon> {{'DESTINATION.ENDPOINT' | translate}}</button> <create-edit-endpoint (reload)="reload($event)"></create-edit-endpoint> </div> <div class="flex-items-xs-middle option-right"> - <hbr-filter filterPlaceholder='{{"REPLICATION.FILTER_TARGETS_PLACEHOLDER" | translate}}' (filter)="doSearchTargets($event)" [currentValue]="targetName"></hbr-filter> - <a href="javascript:void(0)" (click)="refreshTargets()"> + <hbr-filter [withDivider]="true" filterPlaceholder='{{"REPLICATION.FILTER_TARGETS_PLACEHOLDER" | translate}}' (filter)="doSearchTargets($event)" [currentValue]="targetName"></hbr-filter> + <span class="refresh-btn" (click)="refreshTargets()"> <clr-icon shape="refresh"></clr-icon> - </a> + </span> </div> </div> </div> @@ -37,4 +37,6 @@ export const ENDPOINT_TEMPLATE: string = ` </clr-datagrid> </div> </div> + <confirmation-dialog #confirmationDialog (confirmAction)="confirmDeletion($event)"></confirmation-dialog> +</div> `; \ No newline at end of file diff --git a/src/ui_ng/lib/src/filter/filter.component.ts b/src/ui_ng/lib/src/filter/filter.component.ts index 7e6f90a3c..5f7c80ada 100644 --- a/src/ui_ng/lib/src/filter/filter.component.ts +++ b/src/ui_ng/lib/src/filter/filter.component.ts @@ -31,6 +31,7 @@ export class FilterComponent implements OnInit { placeHolder: string = ""; filterTerms = new Subject<string>(); + isExpanded: boolean = false; @Output("filter") private filterEvt = new EventEmitter<string>(); @@ -39,6 +40,8 @@ export class FilterComponent implements OnInit { public set flPlaceholder(placeHolder: string) { this.placeHolder = placeHolder; } + @Input() expandMode: boolean = false; + @Input() withDivider: boolean = false; ngOnInit(): void { this.filterTerms @@ -54,4 +57,16 @@ export class FilterComponent implements OnInit { //Send out filter terms this.filterTerms.next(this.currentValue.trim()); } + + onClick(): void { + //Only enabled when expandMode is set to false + if(this.expandMode){ + return; + } + this.isExpanded = !this.isExpanded; + } + + public get isShowSearchBox(): boolean { + return this.expandMode || (!this.expandMode && this.isExpanded); + } } \ No newline at end of file diff --git a/src/ui_ng/lib/src/filter/filter.template.ts b/src/ui_ng/lib/src/filter/filter.template.ts index 1f55ad227..9bed73db5 100644 --- a/src/ui_ng/lib/src/filter/filter.template.ts +++ b/src/ui_ng/lib/src/filter/filter.template.ts @@ -4,8 +4,9 @@ export const FILTER_TEMPLATE: string = ` <span> - <clr-icon shape="filter" size="12" class="is-solid filter-icon"></clr-icon> - <input type="text" style="padding-left: 15px;" (keyup)="valueChange()" placeholder="{{placeHolder}}" [(ngModel)]="currentValue"/> + <clr-icon shape="search" size="20" class="search-btn" [class.filter-icon]="isShowSearchBox" (click)="onClick()"></clr-icon> + <input [hidden]="!isShowSearchBox" type="text" style="padding-left: 15px;" (keyup)="valueChange()" placeholder="{{placeHolder}}" [(ngModel)]="currentValue"/> + <span class="filter-divider" *ngIf="withDivider"></span> </span> `; @@ -14,4 +15,25 @@ export const FILTER_STYLES: string = ` position: relative; right: -12px; } + +.filter-divider { + display: inline-block; + height: 16px; + width: 2px; + background-color: #cccccc; + padding-top: 12px; + padding-bottom: 12px; + position: relative; + top: 9px; + margin-right: 6px; + margin-left: 6px; +} + +.search-btn { + cursor: pointer; +} + +.search-btn:hover { + color: #007CBB; +} `; \ No newline at end of file diff --git a/src/ui_ng/lib/src/list-replication-rule/list-replication-rule.component.html.ts b/src/ui_ng/lib/src/list-replication-rule/list-replication-rule.component.html.ts index 83e5df4eb..3292a7f42 100644 --- a/src/ui_ng/lib/src/list-replication-rule/list-replication-rule.component.html.ts +++ b/src/ui_ng/lib/src/list-replication-rule/list-replication-rule.component.html.ts @@ -1,6 +1,5 @@ export const LIST_REPLICATION_RULE_TEMPLATE: string = ` -<confirmation-dialog #toggleConfirmDialog (confirmAction)="toggleConfirm($event)"></confirmation-dialog> -<confirmation-dialog #deletionConfirmDialog (confirmAction)="deletionConfirm($event)"></confirmation-dialog> +<div> <clr-datagrid [clrDgLoading]="loading"> <clr-dg-column [clrDgField]="'name'">{{'REPLICATION.NAME' | translate}}</clr-dg-column> <clr-dg-column [clrDgField]="'project_name'" *ngIf="projectScope">{{'REPLICATION.PROJECT' | translate}}</clr-dg-column> @@ -37,4 +36,8 @@ export const LIST_REPLICATION_RULE_TEMPLATE: string = ` {{pagination.firstItem + 1}} - {{pagination.lastItem +1 }} {{'REPLICATION.OF' | translate}} {{pagination.totalItems }} {{'REPLICATION.ITEMS' | translate}} <clr-dg-pagination #pagination [clrDgPageSize]="5"></clr-dg-pagination> </clr-dg-footer> -</clr-datagrid>`; \ No newline at end of file +</clr-datagrid> +<confirmation-dialog #toggleConfirmDialog (confirmAction)="toggleConfirm($event)"></confirmation-dialog> +<confirmation-dialog #deletionConfirmDialog (confirmAction)="deletionConfirm($event)"></confirmation-dialog> +</div> +`; \ No newline at end of file diff --git a/src/ui_ng/lib/src/log/recent-log.component.ts b/src/ui_ng/lib/src/log/recent-log.component.ts index 601f4345f..3e6b411c2 100644 --- a/src/ui_ng/lib/src/log/recent-log.component.ts +++ b/src/ui_ng/lib/src/log/recent-log.component.ts @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, Input } from '@angular/core'; import { Router } from '@angular/router'; import { AccessLogService, @@ -23,6 +23,7 @@ import { ErrorHandler } from '../error-handler/index'; import { Observable } from 'rxjs/Observable'; import { toPromise, CustomComparator } from '../utils'; import { LOG_TEMPLATE, LOG_STYLES } from './recent-log.template'; +import { DEFAULT_PAGE_SIZE } from '../utils'; import { Comparator, State } from 'clarity-angular'; @@ -37,11 +38,12 @@ export class RecentLogComponent implements OnInit { logsCache: AccessLog; loading: boolean = true; currentTerm: string; + @Input() withTitle: boolean = false; - pageSize: number = 15; + pageSize: number = DEFAULT_PAGE_SIZE; currentPage: number = 0; - opTimeComparator: Comparator<AccessLog> = new CustomComparator<AccessLog>('op_time', 'date'); + opTimeComparator: Comparator<AccessLogItem> = new CustomComparator<AccessLogItem>('op_time', 'date'); constructor( private logService: AccessLogService, diff --git a/src/ui_ng/lib/src/log/recent-log.template.ts b/src/ui_ng/lib/src/log/recent-log.template.ts index 95fcf5d1d..9abf1081c 100644 --- a/src/ui_ng/lib/src/log/recent-log.template.ts +++ b/src/ui_ng/lib/src/log/recent-log.template.ts @@ -4,11 +4,11 @@ export const LOG_TEMPLATE: string = ` <div> - <h2 class="h2-log-override">{{'SIDE_NAV.LOGS' | translate}}</h2> + <h2 class="h2-log-override" *ngIf="withTitle">{{'SIDE_NAV.LOGS' | translate}}</h2> <div class="row flex-items-xs-between flex-items-xs-bottom"> <div></div> <div class="action-head-pos"> - <hbr-filter filterPlaceholder='{{"AUDIT_LOG.FILTER_PLACEHOLDER" | translate}}' (filter)="doFilter($event)" [currentValue]="currentTerm"></hbr-filter> + <hbr-filter [withDivider]="true" filterPlaceholder='{{"AUDIT_LOG.FILTER_PLACEHOLDER" | translate}}' (filter)="doFilter($event)" [currentValue]="currentTerm"></hbr-filter> <span (click)="refresh()" class="refresh-btn"> <clr-icon shape="refresh" [hidden]="inProgress" ng-disabled="inProgress"></clr-icon> <span class="spinner spinner-inline" [hidden]="!inProgress"></span> @@ -47,6 +47,7 @@ export const LOG_STYLES: string = ` .action-head-pos { padding-right: 18px; + height: 24px; } .refresh-btn { @@ -54,7 +55,7 @@ export const LOG_STYLES: string = ` } .refresh-btn:hover { - color: #00bfff; + color: #007CBB; } .custom-lines-button { diff --git a/src/ui_ng/lib/src/replication/replication.component.css.ts b/src/ui_ng/lib/src/replication/replication.component.css.ts index 7e5276d15..850dfc259 100644 --- a/src/ui_ng/lib/src/replication/replication.component.css.ts +++ b/src/ui_ng/lib/src/replication/replication.component.css.ts @@ -1,11 +1,18 @@ export const REPLICATION_STYLE: string = ` +.refresh-btn { + cursor: pointer; +} + +.refresh-btn:hover { + color: #007CBB; +} + .option-left { padding-left: 16px; - margin-top: 24px; + margin-top: 12px; } .option-right { padding-right: 16px; - margin-top: 18px; } .option-left-down { diff --git a/src/ui_ng/lib/src/replication/replication.component.html.ts b/src/ui_ng/lib/src/replication/replication.component.html.ts index 9c8f4984c..283a45e3c 100644 --- a/src/ui_ng/lib/src/replication/replication.component.html.ts +++ b/src/ui_ng/lib/src/replication/replication.component.html.ts @@ -1,21 +1,21 @@ export const REPLICATION_TEMPLATE: string = ` <div class="row"> <div class="col-lg-12 col-md-12 col-sm-12 col-xs-12"> - <div class="row flex-items-xs-between"> + <div class="row flex-items-xs-between" style="height:24px;"> <div class="flex-xs-middle option-left"> <button *ngIf="projectId" class="btn btn-link" (click)="openModal()"><clr-icon shape="add"></clr-icon> {{'REPLICATION.REPLICATION_RULE' | translate}}</button> <create-edit-rule [projectId]="projectId" (reload)="reloadRules($event)"></create-edit-rule> </div> <div class="flex-xs-middle option-right"> - <div class="select" style="float: left;"> + <div class="select" style="float: left; top: 9px;"> <select (change)="doFilterRuleStatus($event)"> <option *ngFor="let r of ruleStatus" value="{{r.key}}">{{r.description | translate}}</option> </select> </div> - <hbr-filter filterPlaceholder='{{"REPLICATION.FILTER_POLICIES_PLACEHOLDER" | translate}}' (filter)="doSearchRules($event)" [currentValue]="search.ruleName"></hbr-filter> - <a href="javascript:void(0)" (click)="refreshRules()"> + <hbr-filter [withDivider]="true" filterPlaceholder='{{"REPLICATION.FILTER_POLICIES_PLACEHOLDER" | translate}}' (filter)="doSearchRules($event)" [currentValue]="search.ruleName"></hbr-filter> + <span class="refresh-btn" (click)="refreshRules()"> <clr-icon shape="refresh"></clr-icon> - </a> + </span> </div> </div> </div> @@ -23,14 +23,14 @@ export const REPLICATION_TEMPLATE: string = ` <hbr-list-replication-rule #listReplicationRule [projectId]="projectId" (selectOne)="selectOneRule($event)" (editOne)="openEditRule($event)" (reload)="reloadRules($event)" [loading]="loading" [withReplicationJob]="withReplicationJob" (redirect)="customRedirect($event)"></hbr-list-replication-rule> </div> <div *ngIf="withReplicationJob" class="col-lg-12 col-md-12 col-sm-12 col-xs-12"> - <div class="row flex-items-xs-between"> + <div class="row flex-items-xs-between" style="height:60px;"> <h5 class="flex-items-xs-bottom option-left-down" style="margin-left: 14px;">{{'REPLICATION.REPLICATION_JOBS' | translate}}</h5> <div class="flex-items-xs-bottom option-right-down"> <button class="btn btn-link" (click)="toggleSearchJobOptionalName(currentJobSearchOption)">{{toggleJobSearchOption[currentJobSearchOption] | translate}}</button> - <hbr-filter filterPlaceholder='{{"REPLICATION.FILTER_JOBS_PLACEHOLDER" | translate}}' (filter)="doSearchJobs($event)" [currentValue]="search.repoName" ></hbr-filter> - <a href="javascript:void(0)" (click)="refreshJobs()"> + <hbr-filter [withDivider]="true" filterPlaceholder='{{"REPLICATION.FILTER_JOBS_PLACEHOLDER" | translate}}' (filter)="doSearchJobs($event)" [currentValue]="search.repoName" ></hbr-filter> + <span class="refresh-btn" (click)="refreshJobs()"> <clr-icon shape="refresh"></clr-icon> - </a> + </span> </div> </div> <div class="row flex-items-xs-right option-right" [hidden]="currentJobSearchOption === 0"> diff --git a/src/ui_ng/lib/src/repository-stackview/repository-stackview.component.css.ts b/src/ui_ng/lib/src/repository-stackview/repository-stackview.component.css.ts index fdbaab321..3a0a4588e 100644 --- a/src/ui_ng/lib/src/repository-stackview/repository-stackview.component.css.ts +++ b/src/ui_ng/lib/src/repository-stackview/repository-stackview.component.css.ts @@ -1,14 +1,17 @@ export const REPOSITORY_STACKVIEW_STYLES: string = ` .option-right { padding-right: 16px; - margin-bottom: 12px; } - .sub-grid-custom { position: relative; left: 40px; } - +.refresh-btn { + cursor: pointer; +} +.refresh-btn:hover { + color: #007CBB; +} :host >>> .datagrid .datagrid-body .datagrid-row { overflow-x: hidden; overflow-y: hidden; diff --git a/src/ui_ng/lib/src/repository-stackview/repository-stackview.component.html.ts b/src/ui_ng/lib/src/repository-stackview/repository-stackview.component.html.ts index fe0f6a31a..b9d935914 100644 --- a/src/ui_ng/lib/src/repository-stackview/repository-stackview.component.html.ts +++ b/src/ui_ng/lib/src/repository-stackview/repository-stackview.component.html.ts @@ -1,11 +1,11 @@ export const REPOSITORY_STACKVIEW_TEMPLATE: string = ` -<confirmation-dialog #confirmationDialog (confirmAction)="confirmDeletion($event)"></confirmation-dialog> +<div> <div class="row"> - <div class="col-lg-12 col-md-12 col-sm-12 col-xs-12"> + <div class="col-lg-12 col-md-12 col-sm-12 col-xs-12" style="height: 24px;"> <div class="row flex-items-xs-right option-right"> <div class="flex-xs-middle"> - <hbr-filter filterPlaceholder="{{'REPOSITORY.FILTER_FOR_REPOSITORIES' | translate}}" (filter)="doSearchRepoNames($event)"></hbr-filter> - <a href="javascript:void(0)" (click)="refresh()"><clr-icon shape="refresh"></clr-icon></a> + <hbr-filter [withDivider]="true" filterPlaceholder="{{'REPOSITORY.FILTER_FOR_REPOSITORIES' | translate}}" (filter)="doSearchRepoNames($event)"></hbr-filter> + <span class="refresh-btn" (click)="refresh()"><clr-icon shape="refresh"></clr-icon></span> </div> </div> </div> @@ -31,4 +31,6 @@ export const REPOSITORY_STACKVIEW_TEMPLATE: string = ` </clr-datagrid> </div> </div> +<confirmation-dialog #confirmationDialog (confirmAction)="confirmDeletion($event)"></confirmation-dialog> +</div> `; \ No newline at end of file diff --git a/src/ui_ng/lib/src/tag/tag-detail.component.spec.ts b/src/ui_ng/lib/src/tag/tag-detail.component.spec.ts index 039415b55..ecdbab517 100644 --- a/src/ui_ng/lib/src/tag/tag-detail.component.spec.ts +++ b/src/ui_ng/lib/src/tag/tag-detail.component.spec.ts @@ -8,6 +8,7 @@ import { ErrorHandler } from '../error-handler/error-handler'; import { Tag, VulnerabilitySummary } from '../service/interface'; import { SERVICE_CONFIG, IServiceConfig } from '../service.config'; import { TagService, TagDefaultService, ScanningResultService, ScanningResultDefaultService } from '../service/index'; +import { FilterComponent } from '../filter/index'; describe('TagDetailComponent (inline template)', () => { @@ -47,7 +48,8 @@ describe('TagDetailComponent (inline template)', () => { ], declarations: [ TagDetailComponent, - ResultGridComponent + ResultGridComponent, + FilterComponent ], providers: [ ErrorHandler, diff --git a/src/ui_ng/lib/src/utils.ts b/src/ui_ng/lib/src/utils.ts index 3c5fb9add..cd7c8eb77 100644 --- a/src/ui_ng/lib/src/utils.ts +++ b/src/ui_ng/lib/src/utils.ts @@ -118,4 +118,9 @@ export class CustomComparator<T> implements Comparator<T> { } return comp; } -} \ No newline at end of file +} + +/** + * The default page size + */ +export const DEFAULT_PAGE_SIZE: number = 15; \ No newline at end of file diff --git a/src/ui_ng/lib/src/vulnerability-scanning/result-grid.component.spec.ts b/src/ui_ng/lib/src/vulnerability-scanning/result-grid.component.spec.ts index 1213c62ad..1ef98afa2 100644 --- a/src/ui_ng/lib/src/vulnerability-scanning/result-grid.component.spec.ts +++ b/src/ui_ng/lib/src/vulnerability-scanning/result-grid.component.spec.ts @@ -10,6 +10,7 @@ import { ScanningResultService, ScanningResultDefaultService } from '../service/ import { SERVICE_CONFIG, IServiceConfig } from '../service.config'; import { ErrorHandler } from '../error-handler/index'; import { SharedModule } from '../shared/shared.module'; +import { FilterComponent } from '../filter/index'; describe('ResultGridComponent (inline template)', () => { let component: ResultGridComponent; @@ -26,7 +27,7 @@ describe('ResultGridComponent (inline template)', () => { imports: [ SharedModule ], - declarations: [ResultGridComponent], + declarations: [ResultGridComponent, FilterComponent], providers: [ ErrorHandler, { provide: SERVICE_CONFIG, useValue: testConfig }, diff --git a/src/ui_ng/lib/src/vulnerability-scanning/result-grid.component.ts b/src/ui_ng/lib/src/vulnerability-scanning/result-grid.component.ts index a3d340b62..99e4750f5 100644 --- a/src/ui_ng/lib/src/vulnerability-scanning/result-grid.component.ts +++ b/src/ui_ng/lib/src/vulnerability-scanning/result-grid.component.ts @@ -38,4 +38,12 @@ export class ResultGridComponent implements OnInit { }) .catch(error => { this.errorHandler.error(error) }) } + + filterVulnerabilities(terms: string): void { + console.log(terms); + } + + refresh(): void { + this.loadResults(this.tagId); + } } diff --git a/src/ui_ng/lib/src/vulnerability-scanning/scanning.css.ts b/src/ui_ng/lib/src/vulnerability-scanning/scanning.css.ts index c10a11f7a..5affed773 100644 --- a/src/ui_ng/lib/src/vulnerability-scanning/scanning.css.ts +++ b/src/ui_ng/lib/src/vulnerability-scanning/scanning.css.ts @@ -4,11 +4,9 @@ export const SCANNING_STYLES: string = ` height: 24px; display: inline-block; } - .bar-state { text-align: center !important; } - .scanning-button { height: 24px; margin-top: 0px; @@ -17,62 +15,58 @@ export const SCANNING_STYLES: string = ` top: -6px; position: relative; } - .tip-wrapper { display: inline-block; height: 16px; max-height: 16px; max-width: 150px; } - .tip-position { margin-left: -4px; } - .tip-block { margin-left: -4px; } - .bar-block-high { background-color: red; } - .bar-block-medium { background-color: orange; } - .bar-block-low { background-color: yellow; } - .bar-block-none { background-color: green; } - .bar-block-unknown { background-color: grey; } - .bar-tooltip-font { font-size: 13px; color: #ffffff; } - .bar-tooltip-font-title { font-weight: 600; } - .bar-summary { margin-top: 12px; text-align: left; } - .bar-scanning-time { margin-top: 12px; } - .bar-summary-item { margin-top: 3px; margin-bottom: 3px; } +.option-right { + padding-right: 16px; +} +.refresh-btn { + cursor: pointer; +} +.refresh-btn:hover { + color: #007CBB; +} `; \ No newline at end of file diff --git a/src/ui_ng/lib/src/vulnerability-scanning/scanning.html.ts b/src/ui_ng/lib/src/vulnerability-scanning/scanning.html.ts index a7ee640d6..f65de9497 100644 --- a/src/ui_ng/lib/src/vulnerability-scanning/scanning.html.ts +++ b/src/ui_ng/lib/src/vulnerability-scanning/scanning.html.ts @@ -42,7 +42,16 @@ export const TIP_COMPONENT_HTML: string = ` `; export const GRID_COMPONENT_HTML: string = ` -<div> +<div class="row"> + <div class="col-lg-12 col-md-12 col-sm-12 col-xs-12" style="height: 24px;"> + <div class="row flex-items-xs-right option-right"> + <div class="flex-xs-middle"> + <hbr-filter [withDivider]="true" filterPlaceholder="{{'VULNERABILITY.PLACEHOLDER' | translate}}" (filter)="filterVulnerabilities($event)"></hbr-filter> + <span class="refresh-btn" (click)="refresh()"><clr-icon shape="refresh"></clr-icon></span> + </div> + </div> + </div> + <div class="col-lg-12 col-md-12 col-sm-12 col-xs-12"> <clr-datagrid> <clr-dg-column [clrDgField]="'id'">{{'VULNERABILITY.GRID.COLUMN_ID' | translate}}</clr-dg-column> <clr-dg-column [clrDgField]="'severity'">{{'VULNERABILITY.GRID.COLUMN_SEVERITY' | translate}}</clr-dg-column> @@ -71,6 +80,7 @@ export const GRID_COMPONENT_HTML: string = ` <clr-dg-pagination #pagination [clrDgPageSize]="25" [clrDgTotalItems]="scanningResults.length"></clr-dg-pagination> </clr-dg-footer> </clr-datagrid> + </div> </div> `; From f981415b5b64ee7c51444151c5cd5d57ed5b7b58 Mon Sep 17 00:00:00 2001 From: Steven Zou <szou@vmware.com> Date: Tue, 13 Jun 2017 22:24:38 +0800 Subject: [PATCH 2/3] make tag name clickable in repo-tag-stack view --- src/ui_ng/lib/src/tag/tag.component.html.ts | 2 +- src/ui_ng/lib/src/tag/tag.component.ts | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/ui_ng/lib/src/tag/tag.component.html.ts b/src/ui_ng/lib/src/tag/tag.component.html.ts index e6dd182e5..dcf1a4f7d 100644 --- a/src/ui_ng/lib/src/tag/tag.component.html.ts +++ b/src/ui_ng/lib/src/tag/tag.component.html.ts @@ -27,7 +27,7 @@ export const TAG_TEMPLATE = ` <button class="action-item" (click)="showDigestId(t)">{{'REPOSITORY.COPY_DIGEST_ID' | translate}}</button> <button class="action-item" [hidden]="!hasProjectAdminRole" (click)="deleteTag(t)">{{'REPOSITORY.DELETE' | translate}}</button> </clr-dg-action-overflow> - <clr-dg-cell>{{t.name}}</clr-dg-cell> + <clr-dg-cell><a href="javascript:void(0)" (click)="onTagClick(t)">{{t.name}}</a></clr-dg-cell> <clr-dg-cell>docker pull {{registryUrl}}/{{repoName}}:{{t.name}}</clr-dg-cell> <clr-dg-cell *ngIf="withNotary" [ngSwitch]="t.signature !== null"> <clr-icon shape="check" *ngSwitchCase="true" style="color: #1D5100;"></clr-icon> diff --git a/src/ui_ng/lib/src/tag/tag.component.ts b/src/ui_ng/lib/src/tag/tag.component.ts index 361fcfef4..a32e57db8 100644 --- a/src/ui_ng/lib/src/tag/tag.component.ts +++ b/src/ui_ng/lib/src/tag/tag.component.ts @@ -51,6 +51,7 @@ export class TagComponent implements OnInit { @Input() withNotary: boolean; @Output() refreshRepo = new EventEmitter<boolean>(); + @Output() tagClickEvent = new EventEmitter<Tag>(); tags: Tag[]; @@ -105,7 +106,7 @@ export class TagComponent implements OnInit { this.errorHandler.error('Repo name cannot be unset.'); return; } - + this.retrieve(); } @@ -161,7 +162,14 @@ export class TagComponent implements OnInit { this.showTagManifestOpened = true; } } + selectAndCopy($event: any) { $event.target.select(); } + + onTagClick(tag: Tag): void { + if (tag) { + this.tagClickEvent.emit(tag); + } + } } \ No newline at end of file From 23635b69665d44af34fce1899fd136f4e09ff570 Mon Sep 17 00:00:00 2001 From: Steven Zou <szou@vmware.com> Date: Wed, 14 Jun 2017 00:00:22 +0800 Subject: [PATCH 3/3] add placeholders to the datagird --- src/ui_ng/lib/README.md | 70 +++++++++++++++---- .../src/endpoint/endpoint.component.html.ts | 1 + .../list-replication-rule.component.html.ts | 1 + .../list-repository.component.html.ts | 1 + .../replication/replication.component.html.ts | 1 + .../repository-stackview.component.html.ts | 2 +- .../repository-stackview.component.ts | 17 ++++- src/ui_ng/lib/src/tag/tag.component.html.ts | 1 + 8 files changed, 79 insertions(+), 15 deletions(-) diff --git a/src/ui_ng/lib/README.md b/src/ui_ng/lib/README.md index 6fa8c0ec0..b42a7e74c 100644 --- a/src/ui_ng/lib/README.md +++ b/src/ui_ng/lib/README.md @@ -52,10 +52,9 @@ If no parameters are passed to **'forRoot'**, the module will be initialized wit * **Registry log view** +Use **withTitle** to set whether self-contained a header with title or not. Default is **false**, that means no header is existing. ``` -//No @Input properties - -<hbr-log></hbr-log> +<hbr-log [withTitle]="..."></hbr-log> ``` * **Replication Management View** @@ -85,8 +84,18 @@ If **projectId** is set to the id of specified project, then only show the repli **hasProjectAdminRole** is a user session related property to determined whether the current user has project administrator role. Some action menus might be disabled based on this property. +**tagClickEvent** is an @output event emitter for you to catch the tag click events. + ``` -<hbr-repository-stackview [projectId]="..." [hasSignedIn]="..." [hasProjectAdminRole]="..."></hbr-repository-stackview> +<hbr-repository-stackview [projectId]="..." [hasSignedIn]="..." [hasProjectAdminRole]="..." (tagClickEvent)="watchTagClickEvent($event)"></hbr-repository-stackview> + +... + +watchTagClickEvent(tag: Tag): void { + //Process tag + ... +} + ``` ## Configurations @@ -96,7 +105,7 @@ All the related configurations are defined in the **HarborModuleConfig** interfa The base configuration for the module. Mainly used to define the relevant endpoints of services which are in charge of retrieving data from backend APIs. It's a 'OpaqueToken' and defined by 'IServiceConfig' interface. If **config** is not set, the default value will be used. ``` export const DefaultServiceConfig: IServiceConfig = { - systemInfoEndpoint: "/api/system", + systemInfoEndpoint: "/api/systeminfo", repositoryBaseEndpoint: "/api/repositories", logBaseEndpoint: "/api/logs", targetBaseEndpoint: "/api/targets", @@ -126,6 +135,8 @@ HarborLibraryModule.forRoot({ ``` It supports partially overriding. For the items not overridden, default values will be adopted. The items contained in **config** are: +* **systemInfoEndpoint:** The base endpoint of the service used to get the related system configurations. Default value is "/api/systeminfo". + * **repositoryBaseEndpoint:** The base endpoint of the service used to handle the repositories of registry and/or tags of repository. Default value is "/api/repositories". * **logBaseEndpoint:** The base endpoint of the service used to handle the recent access logs. Default is "/api/logs". @@ -578,32 +589,39 @@ HarborLibraryModule.forRoot({ * **ScanningResultService:** Get the vulnerabilities scanning results for the specified tag. ``` @Injectable() +/** + * Get the vulnerabilities scanning results for the specified tag. + * + * @export + * @abstract + * @class ScanningResultService + */ export class MyScanningResultService extends ScanningResultService { /** * Get the summary of vulnerability scanning result. * * @abstract * @param {string} tagId - * @returns {(Observable<ScanningResultSummary> | Promise<ScanningResultSummary> | ScanningResultSummary)} + * @returns {(Observable<VulnerabilitySummary> | Promise<VulnerabilitySummary> | VulnerabilitySummary)} * * @memberOf ScanningResultService */ - getScanningResultSummary(tagId: string): Observable<ScanningResultSummary> | Promise<ScanningResultSummary> | ScanningResultSummary { - ... - } + getVulnerabilityScanningSummary(tagId: string): Observable<VulnerabilitySummary> | Promise<VulnerabilitySummary> | VulnerabilitySummary{ + ... + } /** * Get the detailed vulnerabilities scanning results. * * @abstract * @param {string} tagId - * @returns {(Observable<ScanningDetailResult[]> | Promise<ScanningDetailResult[]> | ScanningDetailResult[])} + * @returns {(Observable<VulnerabilityItem[]> | Promise<VulnerabilityItem[]> | VulnerabilityItem[])} * * @memberOf ScanningResultService */ - getScanningResults(tagId: string): Observable<ScanningDetailResult[]> | Promise<ScanningDetailResult[]> | ScanningDetailResult[] { - ... - } + getVulnerabilityScanningResults(tagId: string): Observable<VulnerabilityItem[]> | Promise<VulnerabilityItem[]> | VulnerabilityItem[]{ + ... + } } ... @@ -612,4 +630,30 @@ HarborLibraryModule.forRoot({ }) ... +``` + +* **SystemInfoService:** Get related system configurations. +``` +/** + * Get System information about current backend server. + * @abstract + * @class + */ +export class MySystemInfoService extends SystemInfoService { + /** + * Get global system information. + * @abstract + * @returns + */ + getSystemInfo(): Observable<SystemInfo> | Promise<SystemInfo> | SystemInfo { + ... + } +} + +... +HarborLibraryModule.forRoot({ + systemInfoService: { provide: SystemInfoService, useClass: MySystemInfoService } +}) +... + ``` \ No newline at end of file diff --git a/src/ui_ng/lib/src/endpoint/endpoint.component.html.ts b/src/ui_ng/lib/src/endpoint/endpoint.component.html.ts index ebd4ce84d..1a15723a1 100644 --- a/src/ui_ng/lib/src/endpoint/endpoint.component.html.ts +++ b/src/ui_ng/lib/src/endpoint/endpoint.component.html.ts @@ -20,6 +20,7 @@ export const ENDPOINT_TEMPLATE: string = ` <clr-dg-column [clrDgField]="'name'">{{'DESTINATION.NAME' | translate}}</clr-dg-column> <clr-dg-column [clrDgField]="'endpoint'">{{'DESTINATION.URL' | translate}}</clr-dg-column> <clr-dg-column [clrDgSortBy]="creationTimeComparator">{{'DESTINATION.CREATION_TIME' | translate}}</clr-dg-column> + <clr-dg-placeholder>{{'DESTINATION.PLACEHOLDER' | translate }}</clr-dg-placeholder> <clr-dg-row *clrDgItems="let t of targets" [clrDgItem]='t'> <clr-dg-action-overflow> <button class="action-item" (click)="editTarget(t)">{{'DESTINATION.TITLE_EDIT' | translate}}</button> diff --git a/src/ui_ng/lib/src/list-replication-rule/list-replication-rule.component.html.ts b/src/ui_ng/lib/src/list-replication-rule/list-replication-rule.component.html.ts index 3292a7f42..f19268eee 100644 --- a/src/ui_ng/lib/src/list-replication-rule/list-replication-rule.component.html.ts +++ b/src/ui_ng/lib/src/list-replication-rule/list-replication-rule.component.html.ts @@ -7,6 +7,7 @@ export const LIST_REPLICATION_RULE_TEMPLATE: string = ` <clr-dg-column [clrDgField]="'target_name'">{{'REPLICATION.DESTINATION_NAME' | translate}}</clr-dg-column> <clr-dg-column [clrDgSortBy]="startTimeComparator">{{'REPLICATION.LAST_START_TIME' | translate}}</clr-dg-column> <clr-dg-column [clrDgSortBy]="enabledComparator">{{'REPLICATION.ACTIVATION' | translate}}</clr-dg-column> + <clr-dg-placeholder>{{'REPLICATION.PLACEHOLDER' | translate }}</clr-dg-placeholder> <clr-dg-row *clrDgItems="let p of changedRules" [clrDgItem]="p" (click)="selectRule(p)" [style.backgroundColor]="(!projectScope && withReplicationJob && selectedId === p.id) ? '#eee' : ''"> <clr-dg-action-overflow> <button class="action-item" (click)="editRule(p)">{{'REPLICATION.EDIT_POLICY' | translate}}</button> diff --git a/src/ui_ng/lib/src/list-repository/list-repository.component.html.ts b/src/ui_ng/lib/src/list-repository/list-repository.component.html.ts index 1a5e65037..158fac220 100644 --- a/src/ui_ng/lib/src/list-repository/list-repository.component.html.ts +++ b/src/ui_ng/lib/src/list-repository/list-repository.component.html.ts @@ -3,6 +3,7 @@ export const LIST_REPOSITORY_TEMPLATE = ` <clr-dg-column [clrDgField]="'name'">{{'REPOSITORY.NAME' | translate}}</clr-dg-column> <clr-dg-column [clrDgSortBy]="tagsCountComparator">{{'REPOSITORY.TAGS_COUNT' | translate}}</clr-dg-column> <clr-dg-column [clrDgSortBy]="pullCountComparator">{{'REPOSITORY.PULL_COUNT' | translate}}</clr-dg-column> + <clr-dg-placeholder>{{'REPOSITORY.PLACEHOLDER' | translate }}</clr-dg-placeholder> <clr-dg-row *clrDgItems="let r of repositories" [clrDgItem]='r'> <clr-dg-action-overflow [hidden]="!hasProjectAdminRole"> <button class="action-item" (click)="deleteRepo(r.name)">{{'REPOSITORY.DELETE' | translate}}</button> diff --git a/src/ui_ng/lib/src/replication/replication.component.html.ts b/src/ui_ng/lib/src/replication/replication.component.html.ts index 283a45e3c..5e89a2843 100644 --- a/src/ui_ng/lib/src/replication/replication.component.html.ts +++ b/src/ui_ng/lib/src/replication/replication.component.html.ts @@ -53,6 +53,7 @@ export const REPLICATION_TEMPLATE: string = ` <clr-dg-column [clrDgSortBy]="creationTimeComparator">{{'REPLICATION.CREATION_TIME' | translate}}</clr-dg-column> <clr-dg-column [clrDgSortBy]="updateTimeComparator">{{'REPLICATION.END_TIME' | translate}}</clr-dg-column> <clr-dg-column>{{'REPLICATION.LOGS' | translate}}</clr-dg-column> + <clr-dg-placeholder>{{'REPLICATION.JOB_PLACEHOLDER' | translate }}</clr-dg-placeholder> <clr-dg-row *clrDgItems="let j of jobs" [clrDgItem]='j'> <clr-dg-cell>{{j.repository}}</clr-dg-cell> <clr-dg-cell>{{j.status}}</clr-dg-cell> diff --git a/src/ui_ng/lib/src/repository-stackview/repository-stackview.component.html.ts b/src/ui_ng/lib/src/repository-stackview/repository-stackview.component.html.ts index b9d935914..8ab942517 100644 --- a/src/ui_ng/lib/src/repository-stackview/repository-stackview.component.html.ts +++ b/src/ui_ng/lib/src/repository-stackview/repository-stackview.component.html.ts @@ -21,7 +21,7 @@ export const REPOSITORY_STACKVIEW_TEMPLATE: string = ` <clr-dg-cell>{{r.name}}</clr-dg-cell> <clr-dg-cell>{{r.tags_count}}</clr-dg-cell> <clr-dg-cell>{{r.pull_count}}</clr-dg-cell> - <hbr-tag *clrIfExpanded ngProjectAs="clr-dg-row-detail" class="sub-grid-custom" [repoName]="r.name" [registryUrl]="registryUrl" [withNotary]="withNotary" [hasSignedIn]="hasSignedIn" [hasProjectAdminRole]="hasProjectAdminRole" [projectId]="projectId" [isEmbedded]="true" (refreshRepo)="refresh($event)"></hbr-tag> + <hbr-tag *clrIfExpanded ngProjectAs="clr-dg-row-detail" (tagClickEvent)="watchTagClickEvt($event)" class="sub-grid-custom" [repoName]="r.name" [registryUrl]="registryUrl" [withNotary]="withNotary" [hasSignedIn]="hasSignedIn" [hasProjectAdminRole]="hasProjectAdminRole" [projectId]="projectId" [isEmbedded]="true" (refreshRepo)="refresh($event)"></hbr-tag> </clr-dg-row> <clr-dg-footer> {{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'REPOSITORY.OF' | translate}} diff --git a/src/ui_ng/lib/src/repository-stackview/repository-stackview.component.ts b/src/ui_ng/lib/src/repository-stackview/repository-stackview.component.ts index c6d1a5ce3..7321a1134 100644 --- a/src/ui_ng/lib/src/repository-stackview/repository-stackview.component.ts +++ b/src/ui_ng/lib/src/repository-stackview/repository-stackview.component.ts @@ -1,4 +1,13 @@ -import { Component, Input, OnInit, ViewChild, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { + Component, + Input, + Output, + OnInit, + ViewChild, + ChangeDetectionStrategy, + ChangeDetectorRef, + EventEmitter +} from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; import { Comparator } from 'clarity-angular'; @@ -21,6 +30,7 @@ import { ConfirmationDialogComponent } from '../confirmation-dialog/confirmation import { ConfirmationMessage } from '../confirmation-dialog/confirmation-message'; import { ConfirmationAcknowledgement } from '../confirmation-dialog/confirmation-state-message'; import { Subscription } from 'rxjs/Subscription'; +import { Tag } from '../service/interface'; @Component({ selector: 'hbr-repository-stackview', @@ -34,6 +44,7 @@ export class RepositoryStackviewComponent implements OnInit { @Input() hasSignedIn: boolean; @Input() hasProjectAdminRole: boolean; + @Output() tagClickEvent = new EventEmitter<Tag>(); lastFilteredRepoName: string; repositories: Repository[]; @@ -120,4 +131,8 @@ export class RepositoryStackviewComponent implements OnInit { refresh() { this.retrieve(); } + + watchTagClickEvt(tag: Tag): void { + this.tagClickEvent.emit(tag); + } } \ No newline at end of file diff --git a/src/ui_ng/lib/src/tag/tag.component.html.ts b/src/ui_ng/lib/src/tag/tag.component.html.ts index dcf1a4f7d..1fb6ba5f0 100644 --- a/src/ui_ng/lib/src/tag/tag.component.html.ts +++ b/src/ui_ng/lib/src/tag/tag.component.html.ts @@ -22,6 +22,7 @@ export const TAG_TEMPLATE = ` <clr-dg-column [clrDgField]="'docker_version'">{{'REPOSITORY.DOCKER_VERSION' | translate}}</clr-dg-column> <clr-dg-column [clrDgField]="'architecture'">{{'REPOSITORY.ARCHITECTURE' | translate}}</clr-dg-column> <clr-dg-column [clrDgField]="'os'">{{'REPOSITORY.OS' | translate}}</clr-dg-column> + <clr-dg-placeholder>{{'TGA.PLACEHOLDER' | translate }}</clr-dg-placeholder> <clr-dg-row *clrDgItems="let t of tags" [clrDgItem]='t'> <clr-dg-action-overflow> <button class="action-item" (click)="showDigestId(t)">{{'REPOSITORY.COPY_DIGEST_ID' | translate}}</button>