[Fix] 2.0 UI bug

1.fix #11312
2.fix #11235
3.fix #11230
4.fix #11209
5.fix #11199
6.fix #11034
7.fix #9926
Signed-off-by: Yogi_Wang <yawang@vmware.com>
This commit is contained in:
Yogi_Wang 2020-03-27 16:31:04 +08:00
parent 033d6dac6b
commit 661867240d
23 changed files with 132 additions and 51 deletions

View File

@ -0,0 +1,16 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SelectArtifactIconPipe } from './select-artifact-icon/select-artifact-icon.pipe';
@NgModule({
declarations: [SelectArtifactIconPipe],
imports: [
CommonModule
],
exports: [
SelectArtifactIconPipe
]
})
export class AllPipesModule { }

View File

@ -0,0 +1,19 @@
import { SelectArtifactIconPipe } from './select-artifact-icon.pipe';
describe('SelectArtifactIconPipe', () => {
let mockTypeImage = "IMAGE";
let mockTypeChart = "CHART";
let mockTypecnab = "CNAB";
it('create an instance', () => {
const pipe = new SelectArtifactIconPipe();
expect(pipe).toBeTruthy();
});
it('it should success get adress of icon', () => {
const pipe = new SelectArtifactIconPipe();
expect(pipe.transform(mockTypeImage, '')).toBe('images/artifact-image.svg');
expect(pipe.transform(mockTypeChart, '')).toBe('images/artifact-chart.svg');
expect(pipe.transform(mockTypecnab, '')).toBe('images/artifact-cnab.svg');
expect(pipe.transform("", '')).toBe('images/artifact-default.svg');
});
});

View File

@ -0,0 +1,18 @@
import { Pipe, PipeTransform } from '@angular/core';
import { artifactImages, artifactDefault } from '../../project/repository/artifact/artifact';
@Pipe({
name: 'selectArtifactIcon'
})
export class SelectArtifactIconPipe implements PipeTransform {
transform(value: string, ...args: any[]): any {
if (artifactImages.some(image => image === value)) {
return 'images/artifact-' + value.toLowerCase() + '.svg';
} else {
return artifactDefault;
}
}
}

View File

@ -45,7 +45,7 @@ import { LabelsComponent } from './labels/labels.component';
import { ProjectQuotasComponent } from './project-quotas/project-quotas.component';
import { HarborLibraryModule } from "../lib/harbor-library.module";
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { AllPipesModule } from './all-pipes/all-pipes.module';
registerLocaleData(zh, 'zh-cn');
registerLocaleData(es, 'es-es');
registerLocaleData(localeFr, 'fr-fr');
@ -84,7 +84,8 @@ export function getCurrentLanguage(translateService: TranslateService) {
DeveloperCenterModule,
OidcOnboardModule,
LicenseModule,
HarborLibraryModule
HarborLibraryModule,
AllPipesModule
],
exports: [
],

View File

@ -20,6 +20,8 @@ import { AppConfigService } from '../../services/app-config.service';
import { ConfigurationService } from '../config.service';
import { Configuration } from "../../../lib/components/config/config";
import { ErrorHandler } from "../../../lib/utils/error-handler";
import { errorHandler as errorHandlerFn } from "../../../lib/utils/shared/shared.utils";
import { SystemInfoService } from "../../../lib/services";
import { clone, isEmpty, getChanges as getChangesFunc } from "../../../lib/utils/utils";
import { CONFIG_AUTH_MODE } from "../../../lib/entities/shared.const";
@ -142,7 +144,7 @@ export class ConfigurationAuthComponent implements OnChanges, OnInit {
this.msgHandler.showSuccess('CONFIG.TEST_LDAP_SUCCESS');
}, error => {
this.testingOnGoing = false;
let err = error.error;
let err = errorHandlerFn(error);
if (!err || !err.trim()) {
err = 'UNKNOWN';
}

View File

@ -63,6 +63,7 @@ import {
import { ArtifactDefaultService, ArtifactService } from "./repository/artifact/artifact.service";
import { GridViewComponent } from "./repository/gridview/grid-view.component";
import { LastTriggerComponent } from "./webhook/last-trigger/last-trigger.component";
import { AllPipesModule } from '../all-pipes/all-pipes.module';
@NgModule({
imports: [
@ -73,6 +74,7 @@ import { LastTriggerComponent } from "./webhook/last-trigger/last-trigger.compon
HelmChartModule,
SummaryModule,
TagFeatureIntegrationModule,
AllPipesModule
],
declarations: [
ProjectComponent,

View File

@ -161,7 +161,7 @@
<clr-dg-cell class="truncated flex-max-width">
<div class="cell white-normal">
<img class="artifact-icon" [title]="artifact.type"
[src]="artifact.showImage" />
[src]="artifact.type | selectArtifactIcon" />
&nbsp; &nbsp;
<a href="javascript:void(0)" class="max-width-100" (click)="goIntoArtifactSummaryPage(artifact)"
title="{{artifact.digest}}">
@ -202,12 +202,14 @@
</div>
</div>
</div>
<clr-tooltip-content [clrPosition]="'top-right'" [clrSize]="'lg'" *clrIfOpen>
<clr-tooltip-content [clrPosition]="'top-right'" class="lg" [clrSize]="'lg'" *clrIfOpen>
<table class="table table-noborder mt-0 table-tag">
<thead class="tag-thead">
<tr>
<th class="left tag-header-color">
{{'REPOSITORY.TAGS_COUNT' | translate | uppercase}}</th>
<th class="left tag-header-color">
{{'REPOSITORY.SIGNED' | translate | uppercase}}</th>
<th class="left tag-header-color">
{{'REPOSITORY.PULL_TIME' | translate | uppercase}}</th>
<th class="left tag-header-color">
@ -217,6 +219,16 @@
<tbody class="tag-tbody">
<tr class="tag-tr" *ngFor="let tag of artifact.tags">
<td class="left tag-body-color">{{tag.name}}</td>
<td class="left tag-body-color" [ngSwitch]="tag.signed">
<div class="cell">
<clr-icon shape="check-circle" *ngSwitchCase="true" size="20" class="color-green"></clr-icon>
<clr-icon shape="times-circle" *ngSwitchCase="false" size="16" class="color-red"></clr-icon>
<a href="javascript:void(0)" *ngSwitchDefault role="tooltip" aria-haspopup="true" class="tooltip tooltip-top-right">
<clr-icon shape="help" class="color-gray" size="16"></clr-icon>
<span class="tooltip-content">{{'REPOSITORY.NOTARY_IS_UNDETERMINED' | translate}}</span>
</a>
</div>
</td>
<td class="left tag-body-color">{{tag.pull_time === availableTime ? '':(tag.pull_time | date: 'short')}}</td>
<td class="left tag-body-color">{{tag.push_time | date: 'short'}}</td>
</tr>

View File

@ -331,9 +331,12 @@ clr-datagrid {
}
.width-p-100 {
width: 100%;
.lg {
width: 450px;
}
}
.w-rem-4 {
width: 4rem !important;
min-width: 4rem !important;
}
.tag-header-color {
color: #fff;

View File

@ -32,6 +32,7 @@ import { ChannelService } from "../../../../../../lib/services/channel.service";
import { OperationService } from "../../../../../../lib/components/operation/operation.service";
import { By } from "@angular/platform-browser";
import { ArtifactService as NewArtifactService } from "../../../../../../../ng-swagger-gen/services/artifact.service";
import { AllPipesModule } from "../../../../../all-pipes/all-pipes.module";
describe("ArtifactListTabComponent (inline template)", () => {
@ -290,6 +291,7 @@ describe("ArtifactListTabComponent (inline template)", () => {
SharedModule,
BrowserAnimationsModule,
HttpClientTestingModule,
AllPipesModule
],
schemas: [
CUSTOM_ELEMENTS_SCHEMA

View File

@ -12,13 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import {
AfterViewInit,
Component,
ElementRef,
EventEmitter,
Input, OnDestroy,
OnInit,
Output,
ViewChild,
} from "@angular/core";
@ -27,11 +24,9 @@ import { catchError, debounceTime, distinctUntilChanged, finalize, map } from 'r
import { TranslateService } from "@ngx-translate/core";
import { ClrLoadingState, ClrDatagridStateInterface, ClrDatagridComparatorInterface } from "@clr/angular";
import { HttpParams } from "@angular/common/http";
import { ActivatedRoute, Router } from "@angular/router";
import {
Comparator, Label, LabelService, ScanningResultService,
State,
UserPermissionService, USERSTATICPERMISSION, VulnerabilitySummary
} from "../../../../../../lib/services";
import {
@ -59,7 +54,7 @@ import {
} from "../../../../../../lib/entities/shared.const";
import { operateChanges, OperateInfo, OperationState } from "../../../../../../lib/components/operation/operate";
import { errorHandler } from "../../../../../../lib/utils/shared/shared.utils";
import { ArtifactFront as Artifact, mutipleFilter, artifactImages, ArtifactFront } from "../../../artifact/artifact";
import { ArtifactFront as Artifact, mutipleFilter } from "../../../artifact/artifact";
import { Project } from "../../../../project";
import { ArtifactService as NewArtifactService } from "../../../../../../../ng-swagger-gen/services/artifact.service";
import { ADDITIONS } from "../../../artifact/artifact-additions/models";
@ -373,7 +368,6 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy {
})).subscribe(artifacts => {
this.artifactList = artifacts;
this.getArtifactAnnotationsArray(this.artifactList);
this.getArtifactIcon(this.artifactList);
}, error => {
this.errorHandlerService.error(error);
});
@ -401,7 +395,6 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy {
}
this.artifactList = res.body;
this.getArtifactAnnotationsArray(this.artifactList);
this.getArtifactIcon(this.artifactList);
}, error => {
// error
this.errorHandlerService.error(error);
@ -985,13 +978,4 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy {
get isFilterReadonly() {
return this.filterByType === 'labels' ? 'readonly' : null;
}
getArtifactIcon(artifacts: ArtifactFront[]) {
for (const artifact of artifacts) {
if (artifactImages.some(image => image === artifact.type)) {
artifact.showImage = 'images/artifact-' + artifact.type.toLowerCase() + '.svg';
} else {
artifact.showImage = 'images/artifact-default.svg';
}
}
}
}

View File

@ -1,8 +1,8 @@
<ng-container *ngIf="hasCommonProperties()">
<h4 class="margin-bottom-075">{{'ARTIFACT.EXTRA_PROPERTIES' | translate}}</h4>
<h4 class="margin-bottom-075">{{'ARTIFACT.OVERVIEW' | translate}}</h4>
<clr-stack-view>
<clr-stack-block [clrSbExpanded] = "true">
<clr-stack-label>{{'ARTIFACT.EXTRA_PROPERTIES' | translate}}</clr-stack-label>
<clr-stack-label>{{'ARTIFACT.OVERVIEW' | translate}}</clr-stack-label>
<clr-stack-block *ngFor="let item of commonProperties | keyvalue">
<clr-stack-label>{{item?.key}}</clr-stack-label>
<clr-stack-content>{{item?.value}}</clr-stack-content>

View File

@ -36,7 +36,7 @@ export class ArtifactCommonPropertiesComponent implements OnInit, OnChanges {
Object.assign(this.commonProperties, this.artifactDetails.extra_attrs);
for (let name in this.commonProperties) {
if (this.commonProperties.hasOwnProperty(name)) {
if (isObject(this.commonProperties[name])) {
if (typeof (this.commonProperties[name]) === 'object') {
this.commonProperties[name] = JSON.stringify(this.commonProperties[name]);
}
if (name === Types.CREATED) {

View File

@ -1,5 +1,5 @@
<div class="arrow-block" *ngIf="!withAdmiral">
<a (click)="goBackPro()">{{'SIDE_NAV.PROJECTS'| translate}}</a>
<a class="pl-0" (click)="goBackPro()">{{'SIDE_NAV.PROJECTS'| translate}}</a>
<span class="back-icon"><</span>
<a (click)="goBackRep()">{{'REPOSITORY.REPOSITORIES'| translate}}</a>
<span class="back-icon"><</span>
@ -14,17 +14,18 @@
<clr-icon class="rotate-90 arrow-back" shape="arrow" size="36" (click)="onBack()"></clr-icon>
</div>
<div class="title-block">
<h2 class="custom-h2">{{artifact?.digest | slice:0:15}}</h2>
<h2 class="custom-h2 center-align-items"><img class="artifact-icon" [title]="artifact.type"
[src]="artifact.type | selectArtifactIcon" /> {{artifact?.digest | slice:0:15}} <clr-icon size="25" *ngIf="artifact?.references && artifact?.references?.length" class="icon-folder" shape="folder"></clr-icon></h2>
</div>
</div>
<ng-container *ngIf="!loading">
<!-- Extra Attributes -->
<artifact-common-properties [artifactDetails]="artifact"></artifact-common-properties>
<!-- tags -->
<artifact-tag [artifactDetails]="artifact" [projectName]="projectName" [projectId]="projectId" [repositoryName]="repositoryName"
(refreshArtifact)="refreshArtifact()"></artifact-tag>
<!-- Overview -->
<artifact-common-properties [artifactDetails]="artifact"></artifact-common-properties>
<!-- Additions -->
<artifact-additions
[projectName]="projectName"

View File

@ -17,4 +17,17 @@
.center {
justify-content: center;
align-items: center;
}
.center-align-items {
display: flex;
align-items: center;
clr-icon {
margin-left: 10px;
}
img {
margin-right: 10px;
}
}
.artifact-icon {
width: 25px;
}

View File

@ -11,6 +11,7 @@ import { TranslateFakeLoader, TranslateLoader, TranslateModule } from "@ngx-tran
import { ActivatedRoute, Router } from "@angular/router";
import { AppConfigService } from "../../../services/app-config.service";
import { Project } from "../../project";
import { AllPipesModule } from "../../../all-pipes/all-pipes.module";
describe('ArtifactSummaryComponent', () => {
@ -66,6 +67,7 @@ describe('ArtifactSummaryComponent', () => {
TestBed.configureTestingModule({
imports: [
ClarityModule,
AllPipesModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,

View File

@ -51,3 +51,4 @@ export const mutipleFilter = [
export const artifactImages = [
'IMAGE', 'CHART', 'CNAB', 'OPENPOLICYAGENT'
];
export const artifactDefault = "images/artifact-default.svg";

View File

@ -1025,7 +1025,7 @@
"FILTER_FOR_ARTIFACTS": "Filter Artifacts",
"ADDITIONS": "Additions",
"ANNOTATION": "Annotations",
"EXTRA_PROPERTIES": "Extra Attributes",
"OVERVIEW": "Overview",
"IMAGE": "IMAGE",
"CHART": "CHART",
"CNAB": "CNAB",
@ -1155,6 +1155,7 @@
"UNKNOWN": "n/a",
"STATUS": "Status",
"START_TIME": "Start Time",
"CREATION_TIME": "Creation Time",
"UPDATE_TIME": "Update Time",
"LOGS": "Logs",
"PENDING": "Pending",

View File

@ -1024,7 +1024,7 @@
"FILTER_FOR_ARTIFACTS": "Filter Artifacts",
"ADDITIONS": "Additions",
"ANNOTATION": "Annotations",
"EXTRA_PROPERTIES": "Extra Attributes",
"OVERVIEW": "Overview",
"IMAGE": "IMAGE",
"CHART": "CHART",
"CNAB": "CNAB",
@ -1152,6 +1152,7 @@
"UNKNOWN": "n/a",
"STATUS": "Status",
"START_TIME": "Start Time",
"CREATION_TIME": "Creation Time",
"UPDATE_TIME": "Update Time",
"LOGS": "Logs",
"PENDING": "Pending",

View File

@ -997,7 +997,7 @@
"FILTER_FOR_ARTIFACTS": "Filter Artifacts",
"ADDITIONS": "Additions",
"ANNOTATION": "Annotations",
"EXTRA_PROPERTIES": "Extra Attributes",
"OVERVIEW": "Overview",
"IMAGE": "IMAGE",
"CHART": "CHART",
"CNAB": "CNAB",
@ -1123,6 +1123,7 @@
"UNKNOWN": "n. d.",
"STATUS": "Status",
"START_TIME": "Start Time",
"CREATION_TIME": "Creation Time",
"UPDATE_TIME": "Update Time",
"LOGS": "Logs",
"PENDING": "Pending",

View File

@ -1020,7 +1020,7 @@
"FILTER_FOR_ARTIFACTS": "Filter Artifacts",
"ADDITIONS": "Additions",
"ANNOTATION": "Annotations",
"EXTRA_PROPERTIES": "Extra Attributes",
"OVERVIEW": "Overview",
"IMAGE": "IMAGE",
"CHART": "CHART",
"CNAB": "CNAB",
@ -1146,6 +1146,7 @@
"UNKNOWN": "n/a",
"STATUS": "Status",
"START_TIME": "Início",
"CREATION_TIME": "Creation Time",
"END_TIME": "Finalização",
"DETAILS": "Detalhes",
"PENDING": "Pendente",

View File

@ -1025,7 +1025,7 @@
"FILTER_FOR_ARTIFACTS": "Filter Artifacts",
"ADDITIONS": "Additions",
"ANNOTATION": "Annotations",
"EXTRA_PROPERTIES": "Extra Attributes",
"OVERVIEW": "Overview",
"IMAGE": "IMAGE",
"CHART": "CHART",
"CNAB": "CNAB",
@ -1155,6 +1155,7 @@
"UNKNOWN": "n/a",
"STATUS": "Durum",
"START_TIME": "Başlama Zamanı",
"CREATION_TIME": "Creation Time",
"UPDATE_TIME": "Güncelleme Zamanı",
"LOGS": "Kayıtlar",
"PENDING": "Askıda",

View File

@ -1024,7 +1024,7 @@
"FILTER_FOR_ARTIFACTS": "Filter Artifacts",
"ADDITIONS": "其他",
"ANNOTATION": "注解",
"EXTRA_PROPERTIES": "额外属性",
"OVERVIEW": "属性总览",
"IMAGE": "镜像",
"CHART": "CHART",
"CNAB": "CNAB",
@ -1235,8 +1235,8 @@
"DISABLE": "禁用",
"ENABLE": "启用",
"DELETE": "删除",
"ADD_TITLE": "添加Tag保留规则",
"ADD_SUBTITLE": "为当前项目指定tag保留规则。所有tag保留规则独立计算并且适用于所有符合条件的仓库。",
"ADD_TITLE": "添加 Tag 保留规则",
"ADD_SUBTITLE": "为当前项目指定 tag 保留规则。所有 tag 保留规则独立计算并且适用于所有符合条件的仓库。",
"BY_WHAT": "以镜像或天数为条件",
"RULE_TEMPLATE_1": "最近#天的镜像",
"RULE_TEMPLATE_2": "最近活跃的#个镜像",
@ -1250,11 +1250,11 @@
"IN_REPOSITORIES": "应用到仓库",
"REP_SEPARATOR": "使用逗号分隔repos,repo*和**",
"TAGS": "Tags",
"INCLUDE_UNTAGGED": " 不含tag 的 artifacts",
"UNTAGGED": " 不含tag",
"MATCHES_TAGS": "匹配tags",
"MATCHES_EXCEPT_TAGS": "排除tags",
"TAG_SEPARATOR": "输入多个逗号分隔的Tags, Tag*或**。可通过勾选将未加 Tag 的镜像作为此策略的一部分。",
"INCLUDE_UNTAGGED": " 无 Tag 的 Artifacts",
"UNTAGGED": " 无 Tag",
"MATCHES_TAGS": "匹配 tags",
"MATCHES_EXCEPT_TAGS": "排除 tags",
"TAG_SEPARATOR": "输入多个逗号分隔的 Tags, Tag*或**。可通过勾选将未加 Tag 的镜像作为此策略的一部分。",
"LABELS": "标签",
"MATCHES_LABELS": "匹配标签",
"MATCHES_EXCEPT_LABELS": "排除标签",
@ -1299,20 +1299,20 @@
"ACTION": "操作"
},
"IMMUTABLE_TAG": {
"IMMUTABLE_RULES": "不可变的Tag规则",
"IMMUTABLE_RULES": "不可变的 Tag 规则",
"ADD_RULE": "添加新规则",
"ADD_RULE_HELP_1": "点击添加按钮可添加规则。",
"EDIT": "修改",
"DISABLE": "禁用",
"ENABLE": "启用",
"DELETE": "删除",
"ADD_TITLE": "添加不可变的Tag规则",
"ADD_SUBTITLE": "为此项目指定不可变的Tag规则。注意所有不可变的Tag规则都将首先被独立计算合并后最终获得不可变规则的集合。",
"ADD_TITLE": "添加不可变的 Tag 规则",
"ADD_SUBTITLE": "为此项目指定不可变的 Tag 规则。注意:所有不可变的 Tag 规则都将首先被独立计算,合并后最终获得不可变规则的集合。",
"IN_REPOSITORIES": "应用到仓库",
"REP_SEPARATOR": "使用逗号分隔repos,repo*和**。",
"REP_SEPARATOR": "使用逗号分隔 repos,repo* **。",
"TAGS": "Tags",
"TAG_SEPARATOR": "使用逗号分割tags,tag*和**。",
"EDIT_TITLE": "编辑不改变的Tag规则",
"TAG_SEPARATOR": "使用逗号分割 tags,tag* **。",
"EDIT_TITLE": "编辑不改变的 Tag 规则",
"EXC": "排除",
"MAT": "匹配",
"AND": "且",

View File

@ -6,7 +6,7 @@
<clr-dg-column>{{'GC.JOB_ID' | translate}}</clr-dg-column>
<clr-dg-column>{{'GC.TRIGGER_TYPE' | translate}}</clr-dg-column>
<clr-dg-column>{{'STATUS' | translate}}</clr-dg-column>
<clr-dg-column>{{'START_TIME' | translate}}</clr-dg-column>
<clr-dg-column>{{'CREATION_TIME' | translate}}</clr-dg-column>
<clr-dg-column>{{'UPDATE_TIME' | translate}}</clr-dg-column>
<clr-dg-column>{{'LOGS' | translate}}</clr-dg-column>
<clr-dg-row *ngFor="let job of jobs" [clrDgItem]='job'>