Merge pull request #12701 from AllForNothing/artifact-icon

get artifact icon from backend API
This commit is contained in:
Will Sun 2020-08-18 10:29:15 +08:00 committed by GitHub
commit 9671ff1f10
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 112 additions and 69 deletions

View File

@ -151,11 +151,6 @@ export class AddP2pPolicyComponent implements OnInit, OnDestroy {
this.tags = null; this.tags = null;
this.labels = null; this.labels = null;
this.cron = null; this.cron = null;
this.currentForm.reset({
triggerType: "manual",
severity: PROJECT_SEVERITY_LEVEL_MAP[this.projectSeverity],
onlySignedImages: this.enableContentTrust
});
if (this.providers && this.providers.length) { if (this.providers && this.providers.length) {
this.providers.forEach(item => { this.providers.forEach(item => {
if (item.default) { if (item.default) {
@ -163,6 +158,12 @@ export class AddP2pPolicyComponent implements OnInit, OnDestroy {
} }
}); });
} }
this.currentForm.reset({
triggerType: "manual",
severity: PROJECT_SEVERITY_LEVEL_MAP[this.projectSeverity],
onlySignedImages: this.enableContentTrust,
provider: this.policy.provider_id
});
} }
setCron(event: any) { setCron(event: any) {

View File

@ -40,7 +40,7 @@
<div class="execution-select"> <div class="execution-select">
<div class="select filter-tag" [hidden]="!openSelectFilterPiece"> <div class="select filter-tag" [hidden]="!openSelectFilterPiece">
<clr-select-container> <clr-select-container>
<select clrSelect [(ngModel)]="filterByType" (change)="selectFilterType($event)" > <select clrSelect [(ngModel)]="filterByType" (change)="selectFilterType()" >
<option *ngFor="let filter of mutipleFilter" value="{{filter.filterBy}}">{{ filter.filterByShowText | translate}}</option> <option *ngFor="let filter of mutipleFilter" value="{{filter.filterBy}}">{{ filter.filterByShowText | translate}}</option>
</select> </select>
</clr-select-container> </clr-select-container>
@ -161,25 +161,16 @@
<clr-dg-row *ngFor="let artifact of artifactList" [clrDgItem]="artifact" > <clr-dg-row *ngFor="let artifact of artifactList" [clrDgItem]="artifact" >
<clr-dg-cell class="truncated flex-max-width"> <clr-dg-cell class="truncated flex-max-width">
<div class="cell white-normal"> <div class="cell white-normal">
<img *ngIf="artifact?.type !== 'IMAGE';else elseBlock" class="artifact-icon" [title]="artifact.type" <div class="artifact-icon clr-display-inline-block" *ngIf="artifact.icon">
[src]="artifact.type | selectArtifactIcon" /> <img *ngIf="getIcon(artifact.icon)" class="artifact-icon" [title]="artifact.type"
<ng-template #elseBlock> [src]="getIcon(artifact.icon)" (error)="showDefaultIcon($event)" />
<clr-tooltip> </div>
<div clrTooltipTrigger class="level-border">
<img class="artifact-icon" [title]="artifact.type"
[src]="artifact.type | selectArtifactIcon" />
</div>
<clr-tooltip-content clrPosition="top-right" clrSize="lg" *clrIfOpen>
<span>Docker and the Docker logo are trademarks or registered trademarks of Docker, Inc. in the United States and/or other countries.</span>
</clr-tooltip-content>
</clr-tooltip>
</ng-template>
<a href="javascript:void(0)" class="max-width-100 margin-left-5" (click)="goIntoArtifactSummaryPage(artifact)" <a href="javascript:void(0)" class="max-width-100 margin-left-5" (click)="goIntoArtifactSummaryPage(artifact)"
title="{{artifact.digest}}"> title="{{artifact.digest}}">
{{ artifact.digest | slice:0:15}}</a> {{ artifact.digest | slice:0:15}}</a>
<clr-tooltip *ngIf="artifact?.references && artifact?.references?.length"> <clr-tooltip *ngIf="artifact?.references && artifact?.references?.length">
<div clrTooltipTrigger class="level-border"> <div clrTooltipTrigger class="level-border">
<div class="inner truncated "> <div class="inner truncated">
<a href="javascript:void(0)" (click)="goIntoIndexArtifact(artifact)"> <a href="javascript:void(0)" (click)="goIntoIndexArtifact(artifact)">
<clr-icon class="icon-folder" shape="folder"></clr-icon> <clr-icon class="icon-folder" shape="folder"></clr-icon>
</a> </a>
@ -256,7 +247,7 @@
</clr-dg-cell> </clr-dg-cell>
<clr-dg-cell> <clr-dg-cell>
<div class="cell"> <div class="cell">
{{artifact.size?sizeTransform(artifact.size): ""}} {{artifact.size?sizeTransform(artifact.size+''): ""}}
</div> </div>
</clr-dg-cell> </clr-dg-cell>
<clr-dg-cell> <clr-dg-cell>

View File

@ -282,8 +282,13 @@ describe("ArtifactListTabComponent (inline template)", () => {
).pipe(delay(0)); ).pipe(delay(0));
} }
}, },
deleteArtifact: () => of (null) deleteArtifact: () => of (null),
getIconsFromBackEnd() {
return undefined;
},
getIcon() {
return undefined;
}
}; };
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({

View File

@ -54,11 +54,18 @@ import {
} from "../../../../../../lib/entities/shared.const"; } from "../../../../../../lib/entities/shared.const";
import { operateChanges, OperateInfo, OperationState } from "../../../../../../lib/components/operation/operate"; import { operateChanges, OperateInfo, OperationState } from "../../../../../../lib/components/operation/operate";
import { errorHandler } from "../../../../../../lib/utils/shared/shared.utils"; import { errorHandler } from "../../../../../../lib/utils/shared/shared.utils";
import { ArtifactFront as Artifact, mutipleFilter, artifactPullCommands } from "../../../artifact/artifact"; import {
ArtifactFront as Artifact,
mutipleFilter,
artifactPullCommands,
artifactDefault
} from '../../../artifact/artifact';
import { Project } from "../../../../project"; import { Project } from "../../../../project";
import { ArtifactService as NewArtifactService } from "../../../../../../../ng-swagger-gen/services/artifact.service"; import { ArtifactService as NewArtifactService } from "../../../../../../../ng-swagger-gen/services/artifact.service";
import { ADDITIONS } from "../../../artifact/artifact-additions/models"; import { ADDITIONS } from "../../../artifact/artifact-additions/models";
import { Platform } from "../../../../../../../ng-swagger-gen/models/platform"; import { Platform } from "../../../../../../../ng-swagger-gen/models/platform";
import { IconService } from '../../../../../../../ng-swagger-gen/services/icon.service';
import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
export interface LabelState { export interface LabelState {
iconsShow: boolean; iconsShow: boolean;
label: Label; label: Label;
@ -161,7 +168,6 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy {
scanFiinishArtifactLength: number = 0; scanFiinishArtifactLength: number = 0;
onScanArtifactsLength: number = 0; onScanArtifactsLength: number = 0;
constructor( constructor(
private errorHandlerService: ErrorHandler, private errorHandlerService: ErrorHandler,
private userPermissionService: UserPermissionService, private userPermissionService: UserPermissionService,
@ -374,6 +380,7 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy {
artifact.platform = clone(platFormAttr[index].platform); artifact.platform = clone(platFormAttr[index].platform);
}); });
this.getPullCommand(this.artifactList); this.getPullCommand(this.artifactList);
this.getIconsFromBackEnd();
}, error => { }, error => {
this.errorHandlerService.error(error); this.errorHandlerService.error(error);
}); });
@ -403,6 +410,7 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy {
this.artifactList = doSorting<Artifact>(this.artifactList, state); this.artifactList = doSorting<Artifact>(this.artifactList, state);
this.getPullCommand(this.artifactList); this.getPullCommand(this.artifactList);
this.getIconsFromBackEnd();
}, error => { }, error => {
// error // error
this.errorHandlerService.error(error); this.errorHandlerService.error(error);
@ -992,4 +1000,17 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy {
} }
} }
} }
getIconsFromBackEnd() {
if (this.artifactList && this.artifactList.length) {
this.artifactService.getIconsFromBackEnd(this.artifactList);
}
}
showDefaultIcon(event: any) {
if (event && event.target) {
event.target.src = artifactDefault;
}
}
getIcon(icon: string): SafeUrl {
return this.artifactService.getIcon(icon);
}
} }

View File

@ -15,19 +15,10 @@
</div> </div>
<div class="title-block"> <div class="title-block">
<h2 class="custom-h2 center-align-items"> <h2 class="custom-h2 center-align-items">
<img *ngIf="artifact?.type !== 'IMAGE';else elseBlock" class="artifact-icon" [title]="artifact.type" <div class="artifact-icon clr-display-inline-block" *ngIf="artifact.icon">
[src]="artifact.type | selectArtifactIcon" /> <img *ngIf="getIcon(artifact.icon)" class="artifact-icon" [title]="artifact.type"
<ng-template #elseBlock> [src]="getIcon(artifact.icon)" (error)="showDefaultIcon($event)" />
<clr-tooltip> </div>
<div clrTooltipTrigger class="level-border">
<img class="artifact-icon" [title]="artifact.type"
[src]="artifact.type | selectArtifactIcon" />
</div>
<clr-tooltip-content clrPosition="top-right" clrSize="lg" *clrIfOpen>
<span>Docker and the Docker logo are trademarks or registered trademarks of Docker, Inc. in the United States and/or other countries.</span>
</clr-tooltip-content>
</clr-tooltip>
</ng-template>
<span class="margin-left-10px">{{artifact?.digest | slice:0:15}}</span> <span class="margin-left-10px">{{artifact?.digest | slice:0:15}}</span>
<clr-icon size="25" *ngIf="artifact?.references && artifact?.references?.length" class="icon-folder margin-left-10px" shape="folder"></clr-icon> <clr-icon size="25" *ngIf="artifact?.references && artifact?.references?.length" class="icon-folder margin-left-10px" shape="folder"></clr-icon>
</h2> </h2>

View File

@ -12,6 +12,7 @@ import { ActivatedRoute, Router } from "@angular/router";
import { AppConfigService } from "../../../services/app-config.service"; import { AppConfigService } from "../../../services/app-config.service";
import { Project } from "../../project"; import { Project } from "../../project";
import { AllPipesModule } from "../../../all-pipes/all-pipes.module"; import { AllPipesModule } from "../../../all-pipes/all-pipes.module";
import { ArtifactDefaultService } from './artifact.service';
describe('ArtifactSummaryComponent', () => { describe('ArtifactSummaryComponent', () => {
@ -26,9 +27,12 @@ describe('ArtifactSummaryComponent', () => {
} }
}; };
const fakedArtifactService = { const fakedArtifactDefaultService = {
getArtifact() { getIconsFromBackEnd() {
return of(mockedArtifact); return undefined;
},
getIcon() {
return undefined;
} }
}; };
let component: ArtifactSummaryComponent; let component: ArtifactSummaryComponent;
@ -86,7 +90,7 @@ describe('ArtifactSummaryComponent', () => {
{ provide: Router, useValue: mockRouter }, { provide: Router, useValue: mockRouter },
{ provide: ActivatedRoute, useValue: mockActivatedRoute }, { provide: ActivatedRoute, useValue: mockActivatedRoute },
{ provide: ProjectService, useValue: fakedProjectService }, { provide: ProjectService, useValue: fakedProjectService },
{ provide: ArtifactService, useValue: fakedArtifactService }, { provide: ArtifactDefaultService, useValue: fakedArtifactDefaultService },
ErrorHandler ErrorHandler
] ]
}) })

View File

@ -1,14 +1,14 @@
import { Component, Output, EventEmitter, OnInit } from "@angular/core"; import { Component, Output, EventEmitter, OnInit } from "@angular/core";
import { Artifact } from "../../../../../ng-swagger-gen/models/artifact"; import { Artifact } from "../../../../../ng-swagger-gen/models/artifact";
import { ArtifactService } from "../../../../../ng-swagger-gen/services/artifact.service";
import { ErrorHandler } from "../../../../lib/utils/error-handler"; import { ErrorHandler } from "../../../../lib/utils/error-handler";
import { Label } from "../../../../../ng-swagger-gen/models/label"; import { Label } from "../../../../../ng-swagger-gen/models/label";
import { ProjectService } from "../../../../lib/services"; import { ProjectService } from "../../../../lib/services";
import { ActivatedRoute, Router } from "@angular/router"; import { ActivatedRoute, Router } from "@angular/router";
import { AppConfigService } from "../../../services/app-config.service"; import { AppConfigService } from "../../../services/app-config.service";
import { Project } from "../../project"; import { Project } from "../../project";
import { finalize } from "rxjs/operators"; import { artifactDefault } from './artifact';
import { dbEncodeURIComponent } from "../../../../lib/utils/utils"; import { SafeUrl } from '@angular/platform-browser';
import { ArtifactDefaultService } from './artifact.service';
@Component({ @Component({
selector: "artifact-summary", selector: "artifact-summary",
@ -34,11 +34,11 @@ export class ArtifactSummaryComponent implements OnInit {
constructor( constructor(
private projectService: ProjectService, private projectService: ProjectService,
private artifactService: ArtifactService,
private errorHandler: ErrorHandler, private errorHandler: ErrorHandler,
private route: ActivatedRoute, private route: ActivatedRoute,
private appConfigService: AppConfigService, private appConfigService: AppConfigService,
private router: Router private router: Router,
private frontEndArtifactService: ArtifactDefaultService,
) { ) {
} }
@ -81,27 +81,24 @@ export class ArtifactSummaryComponent implements OnInit {
const pro: Project = <Project>(resolverData['artifactResolver'][1]); const pro: Project = <Project>(resolverData['artifactResolver'][1]);
this.projectName = pro.name; this.projectName = pro.name;
this.artifact = <Artifact>(resolverData['artifactResolver'][0]); this.artifact = <Artifact>(resolverData['artifactResolver'][0]);
this.getIconFromBackEnd();
} }
} }
} }
getArtifactDetails(): void {
this.loading = true;
this.artifactService.getArtifact({
repositoryName: dbEncodeURIComponent(this.repositoryName),
reference: this.artifactDigest,
projectName: this.projectName,
withLabel: true,
withScanOverview: true
}).pipe(finalize(() => this.loading = false))
.subscribe(response => {
this.artifact = response;
}, error => {
this.errorHandler.error(error);
});
}
onBack(): void { onBack(): void {
this.backEvt.emit(this.repositoryName); this.backEvt.emit(this.repositoryName);
} }
showDefaultIcon(event: any) {
if (event && event.target) {
event.target.src = artifactDefault;
}
}
getIcon(icon: string): SafeUrl {
return this.frontEndArtifactService.getIcon(icon);
}
getIconFromBackEnd() {
if (this.artifact && this.artifact.icon) {
this.frontEndArtifactService.getIconsFromBackEnd([this.artifact]);
}
}
} }

View File

@ -3,6 +3,8 @@ import { IServiceConfig, SERVICE_CONFIG } from "../../../../lib/entities/service
import { SharedModule } from "../../../../lib/utils/shared/shared.module"; import { SharedModule } from "../../../../lib/utils/shared/shared.module";
import { ArtifactDefaultService, ArtifactService } from "../artifact/artifact.service"; import { ArtifactDefaultService, ArtifactService } from "../artifact/artifact.service";
import { CURRENT_BASE_HREF } from "../../../../lib/utils/utils"; import { CURRENT_BASE_HREF } from "../../../../lib/utils/utils";
import { IconService } from '../../../../../ng-swagger-gen/services/icon.service';
import { DomSanitizer } from '@angular/platform-browser';
describe('ArtifactService', () => { describe('ArtifactService', () => {
@ -16,7 +18,10 @@ describe('ArtifactService', () => {
{ {
provide: ArtifactService, provide: ArtifactService,
useClass: ArtifactDefaultService useClass: ArtifactDefaultService
}] },
IconService,
DomSanitizer
]
}); });
}); });

View File

@ -1,6 +1,9 @@
import { Injectable, Inject } from "@angular/core"; import { Injectable, Inject } from "@angular/core";
import { Subject } from "rxjs"; import { Subject } from "rxjs";
import { IServiceConfig, SERVICE_CONFIG } from "../../../../lib/entities/service.config"; import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
import { Artifact } from '../../../../../ng-swagger-gen/models/artifact';
import { IconService } from '../../../../../ng-swagger-gen/services/icon.service';
/** /**
* Define the service methods to handle the repository tag related things. * Define the service methods to handle the repository tag related things.
@ -13,15 +16,39 @@ export abstract class ArtifactService {
reference: string[]; reference: string[];
triggerUploadArtifact = new Subject<string>(); triggerUploadArtifact = new Subject<string>();
TriggerArtifactChan$ = this.triggerUploadArtifact.asObservable(); TriggerArtifactChan$ = this.triggerUploadArtifact.asObservable();
abstract getIcon(digest: string): SafeUrl;
abstract setIcon(digest: string, url: SafeUrl);
abstract getIconsFromBackEnd(artifactList: Artifact[]);
} }
@Injectable() @Injectable()
export class ArtifactDefaultService extends ArtifactService { export class ArtifactDefaultService extends ArtifactService {
triggerUploadArtifact = new Subject<string>(); triggerUploadArtifact = new Subject<string>();
TriggerArtifactChan$ = this.triggerUploadArtifact.asObservable(); TriggerArtifactChan$ = this.triggerUploadArtifact.asObservable();
private _iconMap: {[key: string]: SafeUrl} = {};
constructor() { constructor(private iconService: IconService,
private domSanitizer: DomSanitizer) {
super(); super();
} }
getIcon(icon: string): SafeUrl {
return this._iconMap[icon];
}
setIcon(icon: string, url: SafeUrl) {
if (!this._iconMap[icon]) {
this._iconMap[icon] = url;
}
}
getIconsFromBackEnd(artifactList: Artifact[]) {
if (artifactList && artifactList.length) {
artifactList.forEach(item => {
if (item.icon && !this.getIcon(item.icon)) {
this.iconService.getIcon({digest: item.icon})
.subscribe(res => {
this.setIcon(item.icon, this.domSanitizer
.bypassSecurityTrustUrl(`data:${res['content-type']};charset=utf-8;base64,${res.content}`));
});
}
});
}
}
} }

View File

@ -5,6 +5,7 @@ export interface ArtifactFront extends Artifact {
platform?: Platform; platform?: Platform;
showImage?: string; showImage?: string;
pullCommand?: string; pullCommand?: string;
annotationsArray?: Array<{[key: string]: any}>;
} }
export const mutipleFilter = [ export const mutipleFilter = [