Add sort fun when filter label in tag page #4617

This commit is contained in:
pfh 2018-04-26 10:24:25 +08:00
parent 9bf38c2486
commit b520addf08
10 changed files with 139 additions and 68 deletions

View File

@ -37,6 +37,7 @@ import {LabelColor} from "../shared/shared.const";
selector: 'hbr-create-edit-label',
template: CREATE_EDIT_LABEL_TEMPLATE,
styles: [CREATE_EDIT_LABEL_STYLE],
changeDetection: ChangeDetectionStrategy.Default
})
export class CreateEditLabelComponent implements OnInit, OnDestroy {
@ -63,6 +64,7 @@ export class CreateEditLabelComponent implements OnInit, OnDestroy {
constructor(
private labelService: LabelService,
private errorHandler: ErrorHandler,
private ref: ChangeDetectorRef
) { }
ngOnInit(): void {
@ -81,6 +83,9 @@ export class CreateEditLabelComponent implements OnInit, OnDestroy {
this.checkOnGoing = false;
this.errorHandler.error(error)
});
setTimeout(() => {
setInterval(() => this.ref.markForCheck(), 100);
}, 1000);
});
}
@ -104,6 +109,7 @@ export class CreateEditLabelComponent implements OnInit, OnDestroy {
openModal(): void {
this.labelModel = this.initLabel();
this.formShow = true;
this.isLabelNameExist = false;
this.labelId = 0;
this.copeLabelModel = null;
}

View File

@ -1,7 +1,6 @@
export const TAG_DETAIL_STYLES: string = `
.overview-section {
padding-bottom: 36px;
border-bottom: 1px solid #cccccc;
}
.detail-section {
@ -60,7 +59,7 @@ export const TAG_DETAIL_STYLES: string = `
.summary-block {
margin-top: 24px;
display: inline-flex;
display: flex;
flex-wrap: row wrap;
}

View File

@ -9,8 +9,8 @@ export const TAG_DETAIL_HTML: string = `
<h2 class="custom-h2">{{repositoryId}}:{{tagDetails.name}}</h2>
</div>
</div>
<div class="summary-block">
<div class="image-summary">
<div class="summary-block row">
<div class="image-summary col-md-4 col-lg-3">
<div class="flex-block">
<div class="image-detail-label">
<div>{{'TAG.AUTHOR' | translate }}</div>
@ -28,7 +28,7 @@ export const TAG_DETAIL_HTML: string = `
</div>
</div>
</div>
<div *ngIf="withClair">
<div *ngIf="withClair" class="col-md-4 col-lg-3">
<div class="vulnerability">
<hbr-vulnerability-bar [repoName]="repositoryId" [tagId]="tagDetails.name" [summary]="tagDetails.scan_overview"></hbr-vulnerability-bar>
</div>

View File

@ -26,7 +26,7 @@ export const TAG_TEMPLATE = `
<div class="form-group"><input type="text" placeholder="Filter labels" [(ngModel)]= "filterName" (keyup)="handleInputFilter()"></div>
<div [hidden]='imageFilterLabels.length' style="padding-left:10px;">{{'LABEL.NO_LABELS' | translate }}</div>
<div [hidden]='!imageFilterLabels.length' style='max-height:300px;overflow-y: auto;'>
<button type="button" class="dropdown-item" *ngFor='let label of imageFilterLabels' (click)="rightFilterLabel(label)">
<button type="button" class="dropdown-item" *ngFor='let label of imageFilterLabels' [hidden]="!label.show" (click)="rightFilterLabel(label)">
<clr-icon shape="check" class='pull-left' [hidden]='!label.iconsShow'></clr-icon>
<div class='labelDiv'><hbr-label-piece [label]="label.label" [labelWidth]="130"></hbr-label-piece></div>
</button>
@ -51,7 +51,7 @@ export const TAG_TEMPLATE = `
<div class="form-group"><input type="text" placeholder="Filter labels" [(ngModel)]="stickName" (keyup)="handleStickInputFilter()"></div>
<div [hidden]='imageStickLabels.length' style="padding-left:10px;">{{'LABEL.NO_LABELS' | translate }}</div>
<div [hidden]='!imageStickLabels.length' style='max-height:300px;overflow-y: auto;'>
<button type="button" class="dropdown-item" *ngFor='let label of imageStickLabels' (click)="stickLabel(label)">
<button type="button" class="dropdown-item" *ngFor='let label of imageStickLabels' [hidden]='!label.show' (click)="stickLabel(label)">
<clr-icon shape="check" class='pull-left' [hidden]='!label.iconsShow'></clr-icon>
<div class='labelDiv'><hbr-label-piece [label]="label.label" [labelWidth]="130"></hbr-label-piece></div>
</button>
@ -69,7 +69,7 @@ export const TAG_TEMPLATE = `
<clr-dg-column style="min-width: 130px;">{{'REPOSITORY.AUTHOR' | translate}}</clr-dg-column>
<clr-dg-column style="width: 160px;"[clrDgSortBy]="createdComparator">{{'REPOSITORY.CREATED' | translate}}</clr-dg-column>
<clr-dg-column style="width: 80px;" [clrDgField]="'docker_version'" *ngIf="!withClair">{{'REPOSITORY.DOCKER_VERSION' | translate}}</clr-dg-column>
<clr-dg-column *ngIf="!withAdmiral" style="width: 140px;" [clrDgField]="'labels'">{{'REPOSITORY.LABELS' | translate}}</clr-dg-column>
<clr-dg-column *ngIf="!withAdmiral" style="width: 140px;">{{'REPOSITORY.LABELS' | translate}}</clr-dg-column>
<clr-dg-placeholder>{{'TAG.PLACEHOLDER' | translate }}</clr-dg-placeholder>
<clr-dg-row *clrDgItems="let t of tags" [clrDgItem]='t'>
<clr-dg-cell class="truncated" style="width: 120px;">

View File

@ -60,12 +60,17 @@ import {BatchInfo, BathInfoChanges} from "../confirmation-dialog/confirmation-ba
import {Observable} from "rxjs/Observable";
import {LabelService} from "../service/label.service";
import {Subject} from "rxjs/Subject";
export interface LabelOpe {
iconsShow: boolean;
label: Label;
show: boolean;
}
@Component({
selector: "hbr-tag",
template: TAG_TEMPLATE,
styles: [TAG_STYLE],
changeDetection: ChangeDetectionStrategy.OnPush
changeDetection: ChangeDetectionStrategy.Default
})
export class TagComponent implements OnInit, AfterViewInit {
@ -103,16 +108,16 @@ export class TagComponent implements OnInit, AfterViewInit {
copyFailed = false;
selectedRow: Tag[] = [];
imageLabels: {[key: string]: boolean | Label | any}[] = [];
imageStickLabels: {[key: string]: boolean | Label | any}[] = [];
imageFilterLabels: {[key: string]: boolean | Label | any}[] = [];
imageLabels: LabelOpe[] = [];
imageStickLabels: LabelOpe[] = [];
imageFilterLabels: LabelOpe[] = [];
labelListOpen = false;
selectedTag: Tag[];
labelNameFilter: Subject<string> = new Subject<string> ();
stickLabelNameFilter: Subject<string> = new Subject<string> ();
filterOnGoing: boolean;
stickName = ''
stickName = '';
filterName = '';
initFilter = {
name: '',
@ -120,7 +125,7 @@ export class TagComponent implements OnInit, AfterViewInit {
color: '',
scope: '',
project_id: 0,
}
};
filterOneLabel: Label = this.initFilter;
@ -163,13 +168,14 @@ export class TagComponent implements OnInit, AfterViewInit {
.subscribe((name: string) => {
if (this.filterName.length) {
this.filterOnGoing = true;
this.imageFilterLabels = [];
this.imageLabels.forEach(data => {
this.imageFilterLabels.forEach(data => {
if (data.label.name.indexOf(this.filterName) !== -1) {
this.imageFilterLabels.push(data);
data.show = true;
} else {
data.show = false;
}
})
});
setTimeout(() => {
setInterval(() => this.ref.markForCheck(), 200);
}, 1000);
@ -182,11 +188,12 @@ export class TagComponent implements OnInit, AfterViewInit {
.subscribe((name: string) => {
if (this.stickName.length) {
this.filterOnGoing = true;
this.imageStickLabels = [];
this.imageLabels.forEach(data => {
this.imageStickLabels.forEach(data => {
if (data.label.name.indexOf(this.stickName) !== -1) {
this.imageStickLabels.push(data);
data.show = true;
}else {
data.show = false;
}
})
setTimeout(() => {
@ -273,14 +280,14 @@ export class TagComponent implements OnInit, AfterViewInit {
toPromise<Label[]>(this.labelService.getGLabels()).then((res: Label[]) => {
if (res.length) {
res.forEach(data => {
this.imageLabels.push({'iconsShow': false, 'label': data});
this.imageLabels.push({'iconsShow': false, 'label': data, 'show': true});
});
}
toPromise<Label[]>(this.labelService.getPLabels(this.projectId)).then((res1: Label[]) => {
if (res1.length) {
res1.forEach(data => {
this.imageLabels.push({'iconsShow': false, 'label': data});
this.imageLabels.push({'iconsShow': false, 'label': data, 'show': true});
});
}
this.imageFilterLabels = clone(this.imageLabels);
@ -294,24 +301,31 @@ export class TagComponent implements OnInit, AfterViewInit {
}
labelSelectedChange(tag?: Tag[]): void {
if (tag && tag[0].labels && tag[0].labels.length) {
if (tag && tag[0].labels) {
this.imageStickLabels.forEach(data => {
data.iconsShow = false;
data.show = true;
})
tag[0].labels.forEach((labelInfo: Label) => {
this.imageStickLabels.find(data => labelInfo.id === data['label'].id).iconsShow = true;
});
if (tag[0].labels.length) {
tag[0].labels.forEach((labelInfo: Label) => {
let findedLabel = this.imageStickLabels.find(data => labelInfo.id === data['label'].id);
this.imageStickLabels.splice(this.imageStickLabels.indexOf(findedLabel), 1);
this.imageStickLabels.unshift(findedLabel);
findedLabel.iconsShow = true;
});
}
}
}
addLabels(tag: Tag[]): void {
this.labelListOpen = true;
this.selectedTag = tag;
this.stickName = '';
this.labelSelectedChange(tag);
}
stickLabel(labelInfo: {[key: string]: any | string[]}): void {
stickLabel(labelInfo: LabelOpe): void {
if (labelInfo && !labelInfo.iconsShow) {
this.selectLabel(labelInfo);
}
@ -320,13 +334,18 @@ export class TagComponent implements OnInit, AfterViewInit {
}
}
selectLabel(labelInfo: {[key: string]: any | string[]}): void {
selectLabel(labelInfo: LabelOpe): void {
if (!this.inprogress) {
this.inprogress = true;
let labelId = labelInfo.label.id;
this.selectedRow = this.selectedTag;
toPromise<any>(this.tagService.addLabelToImages(this.repoName, this.selectedRow[0].name, labelId)).then(res => {
this.refresh();
// set the selected label in front
this.imageStickLabels.splice(this.imageStickLabels.indexOf(labelInfo), 1);
this.imageStickLabels.unshift(labelInfo);
labelInfo.iconsShow = true;
this.inprogress = false;
}).catch(err => {
@ -336,13 +355,15 @@ export class TagComponent implements OnInit, AfterViewInit {
}
}
unSelectLabel(labelInfo: {[key: string]: any | string[]}): void {
unSelectLabel(labelInfo: LabelOpe): void {
if (!this.inprogress) {
this.inprogress = true;
let labelId = labelInfo.label.id;
this.selectedRow = this.selectedTag;
toPromise<any>(this.tagService.deleteLabelToImages(this.repoName, this.selectedRow[0].name, labelId)).then(res => {
this.refresh();
// insert the unselected label to groups with the same icons
this.sortOperation(this.imageStickLabels, labelInfo);
labelInfo.iconsShow = false;
this.inprogress = false;
}).catch(err => {
@ -352,7 +373,7 @@ export class TagComponent implements OnInit, AfterViewInit {
}
}
rightFilterLabel(labelInfo: {[key: string]: any | string[]}): void {
rightFilterLabel(labelInfo: LabelOpe): void {
if (labelInfo) {
if (!labelInfo.iconsShow) {
this.filterLabel(labelInfo);
@ -362,19 +383,26 @@ export class TagComponent implements OnInit, AfterViewInit {
}
}
filterLabel(labelInfo: {[key: string]: any | string[]}): void {
let labelName = labelInfo.label.name;
this.imageFilterLabels.filter(data => {
if (data.label.name !== labelName) {
data.iconsShow = false;
}else {
data.iconsShow = true;
}
});
filterLabel(labelInfo: LabelOpe): void {
let labelName = labelInfo.label.name;
// insert the unselected label to groups with the same icons
let preLabelInfo = this.imageFilterLabels.find(data => data.label.id === this.filterOneLabel.id);
if (preLabelInfo) {
this.sortOperation(this.imageFilterLabels, preLabelInfo);
}
this.imageFilterLabels.filter(data => {
if (data.label.name !== labelName) {
data.iconsShow = false;
}else {
data.iconsShow = true;
}
});
this.imageFilterLabels.splice(this.imageFilterLabels.indexOf(labelInfo), 1);
this.imageFilterLabels.unshift(labelInfo);
this.filterOneLabel = labelInfo.label;
// reload datagu
// reload data
this.currentPage = 1;
let st: State = this.currentState;
if (!st) {
@ -392,31 +420,35 @@ export class TagComponent implements OnInit, AfterViewInit {
this.clrLoad(st);
}
unFilterLabel(labelInfo: {[key: string]: any | string[]}): void {
this.filterOneLabel = this.initFilter;
labelInfo.iconsShow = false;
// reload datagu
this.currentPage = 1;
let st: State = this.currentState;
if (!st) {
st = { page: {} };
}
st.page.size = this.pageSize;
st.page.from = 0;
st.page.to = this.pageSize - 1;
if (this.lastFilteredTagName) {
st.filters = [{property: 'name', value: this.lastFilteredTagName}];
}else {
st.filters = [];
}
this.clrLoad(st);
unFilterLabel(labelInfo: LabelOpe): void {
// insert the unselected label to groups with the same icons
this.sortOperation(this.imageFilterLabels, labelInfo);
this.filterOneLabel = this.initFilter;
labelInfo.iconsShow = false;
// reload data
this.currentPage = 1;
let st: State = this.currentState;
if (!st) {
st = { page: {} };
}
st.page.size = this.pageSize;
st.page.from = 0;
st.page.to = this.pageSize - 1;
if (this.lastFilteredTagName) {
st.filters = [{property: 'name', value: this.lastFilteredTagName}];
}else {
st.filters = [];
}
this.clrLoad(st);
}
handleInputFilter() {
if (this.filterName.length) {
this.labelNameFilter.next(this.filterName);
}else {
this.imageFilterLabels = clone(this.imageLabels);
this.imageFilterLabels.every(data => data.show = true);
}
}
@ -424,10 +456,28 @@ export class TagComponent implements OnInit, AfterViewInit {
if (this.stickName.length) {
this.stickLabelNameFilter.next(this.stickName);
}else {
this.imageStickLabels = clone(this.imageLabels);
this.imageStickLabels.every(data => data.show = true);
}
}
// insert the unselected label to groups with the same icons
sortOperation(labelList: LabelOpe[], labelInfo: LabelOpe): void {
labelList.some((data, i) => {
if (!data.iconsShow) {
if (data.label.scope === labelInfo.label.scope) {
labelList.splice(i, 0, labelInfo);
labelList.splice(labelList.indexOf(labelInfo, 0), 1);
return true;
}
if (data.label.scope !== labelInfo.label.scope && i === labelList.length - 1) {
labelList.push(labelInfo);
labelList.splice(labelList.indexOf(labelInfo), 1);
return true;
}
}
});
}
retrieve() {
this.tags = [];
let signatures: string[] = [] ;

View File

@ -11,6 +11,7 @@ import { SERVICE_CONFIG, IServiceConfig } from '../service.config';
import { ErrorHandler } from '../error-handler/index';
import { SharedModule } from '../shared/shared.module';
import { FilterComponent } from '../filter/index';
import {ChannelService} from "../channel/channel.service";
describe('ResultGridComponent (inline template)', () => {
let component: ResultGridComponent;
@ -30,6 +31,7 @@ describe('ResultGridComponent (inline template)', () => {
declarations: [ResultGridComponent, FilterComponent],
providers: [
ErrorHandler,
ChannelService,
{ provide: SERVICE_CONFIG, useValue: testConfig },
{ provide: ScanningResultService, useClass: ScanningResultDefaultService }
]

View File

@ -9,6 +9,7 @@ import { ErrorHandler } from '../error-handler/index';
import { toPromise } from '../utils';
import { GRID_COMPONENT_HTML } from './scanning.html';
import { SCANNING_STYLES } from './scanning.css';
import {ChannelService} from "../channel/channel.service";
@Component({
selector: 'hbr-vulnerabilities-grid',
@ -24,6 +25,7 @@ export class ResultGridComponent implements OnInit {
constructor(
private scanningService: ScanningResultService,
private channel: ChannelService,
private errorHandler: ErrorHandler
) { }
@ -74,4 +76,8 @@ export class ResultGridComponent implements OnInit {
let reg = new RegExp('.*' + terms + '.*', 'i');
return reg.test(testedValue);
}
scanNow(): void {
this.channel.publishScanEvent(this.repositoryId + "/" + this.tagId);
}
}

View File

@ -126,5 +126,10 @@ hr{
.font-weight-600{
font-weight:600;
}
.rightPos{
position: absolute;
z-index: 100;
right: 35px;
margin-top: 4px;
}
`;

View File

@ -67,10 +67,10 @@ export const TIP_COMPONENT_HTML: string = `
`;
export const GRID_COMPONENT_HTML: string = `
<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">
<div class="row" style="position:relative;">
<div>
<div class="row flex-items-xs-right rightPos">
<div class="flex-xs-middle option-right">
<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>
@ -78,6 +78,9 @@ export const GRID_COMPONENT_HTML: string = `
</div>
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
<clr-datagrid>
<clr-dg-action-bar>
<button type="button" class="btn btn-sm btn-secondary" (click)="scanNow()"><clr-icon shape="shield-check" size="16"></clr-icon>&nbsp;{{'VULNERABILITY.SCAN_NOW' | translate}}</button>
</clr-dg-action-bar>
<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>
<clr-dg-column [clrDgField]="'package'">{{'VULNERABILITY.GRID.COLUMN_PACKAGE' | translate}}</clr-dg-column>

View File

@ -30,7 +30,7 @@
"clarity-icons": "^0.10.27",
"clarity-ui": "^0.10.27",
"core-js": "^2.4.1",
"harbor-ui": "0.7.6",
"harbor-ui": "0.7.7",
"intl": "^1.2.5",
"mutationobserver-shim": "^0.3.2",
"ngx-cookie": "^1.0.0",