mirror of
https://github.com/goharbor/harbor.git
synced 2024-08-20 02:52:49 +02:00
commit
b5cbba0206
|
@ -74,6 +74,7 @@ before_script:
|
|||
- sudo chmod 777 /tmp/registry.db
|
||||
|
||||
script:
|
||||
- sudo cp ./src/ui_ng/package.json ./src/ui_ng/src
|
||||
- sudo mkdir -p /etc/ui/ca/
|
||||
- sudo mv ./tests/ca.crt /etc/ui/ca/
|
||||
- sudo mkdir -p /harbor
|
||||
|
|
|
@ -18,6 +18,7 @@ if [ ! -z "$npm_proxy" -a "$npm_proxy" != " " ]; then
|
|||
npm config set proxy $npm_proxy
|
||||
fi
|
||||
|
||||
cp ./src/package.json .
|
||||
npm install
|
||||
|
||||
./node_modules/.bin/ngc -p tsconfig-aot.json
|
||||
|
|
|
@ -48,8 +48,8 @@ export const TAG_DETAIL_HTML: string = `
|
|||
</div>
|
||||
</div>
|
||||
<div class="second-column">
|
||||
<div>{{highCount}} {{'VULNERABILITY.SEVERITY.HIGH' | translate }} {{suffixForHigh | translate }}</div>
|
||||
<div class="second-row">{{mediumCount}} {{'VULNERABILITY.SEVERITY.MEDIUM' | translate }} {{suffixForMedium | translate }}</div>
|
||||
<div>{{highCount}} {{getPackageText(highCount) | translate}} {{'VULNERABILITY.SEVERITY.HIGH' | translate }} {{suffixForHigh | translate }}</div>
|
||||
<div class="second-row">{{mediumCount}} {{getPackageText(mediumCount) | translate}} {{'VULNERABILITY.SEVERITY.MEDIUM' | translate }} {{suffixForMedium | translate }}</div>
|
||||
</div>
|
||||
<div class="third-column">
|
||||
<div>
|
||||
|
@ -60,8 +60,8 @@ export const TAG_DETAIL_HTML: string = `
|
|||
</div>
|
||||
</div>
|
||||
<div class="fourth-column">
|
||||
<div>{{lowCount}} {{'VULNERABILITY.SEVERITY.LOW' | translate }} {{suffixForLow | translate }}</div>
|
||||
<div class="second-row">{{unknownCount}} {{'VULNERABILITY.SEVERITY.UNKNOWN' | translate }} {{suffixForUnknown | translate }}</div>
|
||||
<div>{{lowCount}} {{getPackageText(lowCount) | translate}} {{'VULNERABILITY.SEVERITY.LOW' | translate }} {{suffixForLow | translate }}</div>
|
||||
<div class="second-row">{{unknownCount}} {{getPackageText(unknownCount) | translate}} {{'VULNERABILITY.SEVERITY.UNKNOWN' | translate }} {{suffixForUnknown | translate }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -144,7 +144,7 @@ describe('TagDetailComponent (inline template)', () => {
|
|||
expect(el).toBeTruthy();
|
||||
let el2: HTMLElement = el.querySelector('div');
|
||||
expect(el2).toBeTruthy();
|
||||
expect(el2.textContent.trim()).toEqual("13 VULNERABILITY.SEVERITY.HIGH VULNERABILITY.PLURAL");
|
||||
expect(el2.textContent.trim()).toEqual("13 VULNERABILITY.PACKAGES VULNERABILITY.SEVERITY.HIGH VULNERABILITY.PLURAL");
|
||||
});
|
||||
}));
|
||||
|
||||
|
|
|
@ -75,8 +75,12 @@ export class TagDetailComponent implements OnInit {
|
|||
this.backEvt.emit(this.tagId);
|
||||
}
|
||||
|
||||
getPackageText(count: number): string {
|
||||
return count > 1 ? "VULNERABILITY.PACKAGES" : "VULNERABILITY.PACKAGE";
|
||||
}
|
||||
|
||||
public get author(): string {
|
||||
return this.tagDetails && this.tagDetails.author? this.tagDetails.author: 'TAG.ANONYMITY';
|
||||
return this.tagDetails && this.tagDetails.author ? this.tagDetails.author : 'TAG.ANONYMITY';
|
||||
}
|
||||
|
||||
public get highCount(): number {
|
||||
|
|
|
@ -37,4 +37,9 @@ export const TAG_STYLE = `
|
|||
white-space: nowrap;
|
||||
text-overflow:ellipsis;
|
||||
}
|
||||
|
||||
.copy-failed {
|
||||
color: red;
|
||||
margin-right: 6px;
|
||||
}
|
||||
`;
|
|
@ -4,11 +4,12 @@ export const TAG_TEMPLATE = `
|
|||
<h3 class="modal-title">{{ manifestInfoTitle | translate }}</h3>
|
||||
<div class="modal-body">
|
||||
<div class="row col-md-12">
|
||||
<textarea rows="3" (click)="selectAndCopy($event)">{{digestId}}</textarea>
|
||||
<textarea rows="2" #digestTarget>{{digestId}}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-primary" (click)="showTagManifestOpened = false">{{'BUTTON.OK' | translate}}</button>
|
||||
<span class="copy-failed" [hidden]="!copyFailed">{{'TAG.COPY_ERROR' | translate}}</span>
|
||||
<button type="button" class="btn btn-primary" [ngxClipboard]="digestTarget" (cbOnSuccess)="onSuccess($event)" (cbOnError)="onError($event)">{{'BUTTON.COPY' | translate}}</button>
|
||||
</div>
|
||||
</clr-modal>
|
||||
|
||||
|
@ -54,6 +55,6 @@ export const TAG_TEMPLATE = `
|
|||
<clr-dg-footer>
|
||||
{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'REPOSITORY.OF' | translate}}
|
||||
{{pagination.totalItems}} {{'REPOSITORY.ITEMS' | translate}}
|
||||
<clr-dg-pagination #pagination [clrDgPageSize]="5"></clr-dg-pagination>
|
||||
<clr-dg-pagination #pagination [clrDgPageSize]="10"></clr-dg-pagination>
|
||||
</clr-dg-footer>
|
||||
</clr-datagrid>`;
|
|
@ -20,6 +20,7 @@ import {
|
|||
EventEmitter,
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
ElementRef,
|
||||
OnDestroy
|
||||
} from '@angular/core';
|
||||
|
||||
|
@ -87,9 +88,13 @@ export class TagComponent implements OnInit, OnDestroy {
|
|||
tagsInScanning: { [key: string]: any } = {};
|
||||
scanningTagCount: number = 0;
|
||||
|
||||
copyFailed: boolean = false;
|
||||
|
||||
@ViewChild('confirmationDialog')
|
||||
confirmationDialog: ConfirmationDialogComponent;
|
||||
|
||||
@ViewChild('digestTarget') textInput: ElementRef;
|
||||
|
||||
constructor(
|
||||
private errorHandler: ErrorHandler,
|
||||
private tagService: TagService,
|
||||
|
@ -195,13 +200,10 @@ export class TagComponent implements OnInit, OnDestroy {
|
|||
this.manifestInfoTitle = 'REPOSITORY.COPY_DIGEST_ID';
|
||||
this.digestId = tag.digest;
|
||||
this.showTagManifestOpened = true;
|
||||
this.copyFailed = false;
|
||||
}
|
||||
}
|
||||
|
||||
selectAndCopy($event: any) {
|
||||
$event.target.select();
|
||||
}
|
||||
|
||||
|
||||
onTagClick(tag: Tag): void {
|
||||
if (tag) {
|
||||
let evt: TagClickEvent = {
|
||||
|
@ -255,4 +257,19 @@ export class TagComponent implements OnInit, OnDestroy {
|
|||
let hnd = setInterval(() => this.ref.markForCheck(), 100);
|
||||
setTimeout(() => clearInterval(hnd), 1000);
|
||||
}
|
||||
|
||||
onSuccess($event: any): void {
|
||||
this.copyFailed = false;
|
||||
//Directly close dialog
|
||||
this.showTagManifestOpened = false;
|
||||
}
|
||||
|
||||
onError($event: any): void {
|
||||
//Show error
|
||||
this.copyFailed = true;
|
||||
//Select all text
|
||||
if(this.textInput){
|
||||
this.textInput.nativeElement.select();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,16 +1,34 @@
|
|||
export const SCANNING_STYLES: string = `
|
||||
.bar-wrapper {
|
||||
width: 120px;
|
||||
height: 12px;
|
||||
}
|
||||
.bar-state {
|
||||
text-align: center !important;
|
||||
}
|
||||
|
||||
.bar-state-chart {
|
||||
position: relative;
|
||||
top: 2px;
|
||||
}
|
||||
|
||||
.bar-state-error {
|
||||
position: relative;
|
||||
top: -3px;
|
||||
}
|
||||
|
||||
.error-text {
|
||||
position: relative;
|
||||
top: 1px;
|
||||
margin-left: -5px;
|
||||
}
|
||||
|
||||
.scanning-button {
|
||||
height: 24px;
|
||||
margin-top: 0px;
|
||||
margin-bottom: 0px;
|
||||
vertical-align: middle;
|
||||
top: -6px;
|
||||
top: -12px;
|
||||
position: relative;
|
||||
}
|
||||
.tip-wrapper {
|
||||
|
|
|
@ -56,7 +56,7 @@ export const GRID_COMPONENT_HTML: string = `
|
|||
<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>
|
||||
<clr-dg-column [clrDgField]="'version'">{{'VULNERABILITY.GRID.COLUMN_VERSION' | translate}} version</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'version'">{{'VULNERABILITY.GRID.COLUMN_VERSION' | translate}}</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'fixedVersion'">{{'VULNERABILITY.GRID.COLUMN_FIXED' | translate}}</clr-dg-column>
|
||||
|
||||
<clr-dg-placeholder>{{'VULNERABILITY.GRID.PLACEHOLDER' | translate}}</clr-dg-placeholder>
|
||||
|
@ -94,15 +94,15 @@ export const BAR_CHART_COMPONENT_HTML: string = `
|
|||
<div *ngIf="queued" class="bar-state">
|
||||
<span>{{'VULNERABILITY.STATE.QUEUED' | translate}}</span>
|
||||
</div>
|
||||
<div *ngIf="error" class="bar-state">
|
||||
<div *ngIf="error" class="bar-state bar-state-error">
|
||||
<clr-icon shape="info-circle" class="is-error" size="24"></clr-icon>
|
||||
<span style="margin-left:-5px;">{{'VULNERABILITY.STATE.ERROR' | translate}}</span>
|
||||
<span class="error-text">{{'VULNERABILITY.STATE.ERROR' | translate}}</span>
|
||||
</div>
|
||||
<div *ngIf="scanning" class="bar-state">
|
||||
<div *ngIf="scanning" class="bar-state bar-state-chart">
|
||||
<div>{{'VULNERABILITY.STATE.SCANNING' | translate}}</div>
|
||||
<div class="progress loop" style="height:2px;min-height:2px;"><progress></progress></div>
|
||||
</div>
|
||||
<div *ngIf="completed" class="bar-state">
|
||||
<div *ngIf="completed" class="bar-state bar-state-chart" style="z-index:1020;">
|
||||
<hbr-vulnerability-summary-chart [summary]="summary"></hbr-vulnerability-summary-chart>
|
||||
</div>
|
||||
<div *ngIf="unknown" class="bar-state">
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
"clarity-icons": "^0.9.8",
|
||||
"clarity-ui": "^0.9.8",
|
||||
"core-js": "^2.4.1",
|
||||
"harbor-ui": "^0.2.13",
|
||||
"harbor-ui": "^0.2.19",
|
||||
"intl": "^1.2.5",
|
||||
"mutationobserver-shim": "^0.3.2",
|
||||
"ngx-cookie": "^1.0.0",
|
||||
|
|
|
@ -11,6 +11,6 @@
|
|||
</clr-dg-row>
|
||||
<clr-dg-footer>
|
||||
{{(projects ? projects.length : 0)}} {{'PROJECT.ITEMS' | translate}}
|
||||
<clr-dg-pagination [clrDgPageSize]="5"></clr-dg-pagination>
|
||||
<clr-dg-pagination [clrDgPageSize]="15"></clr-dg-pagination>
|
||||
</clr-dg-footer>
|
||||
</clr-datagrid>
|
|
@ -9,6 +9,6 @@
|
|||
</clr-dg-row>
|
||||
<clr-dg-footer>
|
||||
{{(repositories ? repositories.length : 0)}} {{'REPOSITORY.ITEMS' | translate}}
|
||||
<clr-dg-pagination [clrDgPageSize]="3"></clr-dg-pagination>
|
||||
<clr-dg-pagination [clrDgPageSize]="15"></clr-dg-pagination>
|
||||
</clr-dg-footer>
|
||||
</clr-datagrid>
|
|
@ -63,8 +63,8 @@ const uiLibConfig: IServiceConfig = {
|
|||
enablei18Support: true,
|
||||
langCookieKey: "harbor-lang",
|
||||
langMessageLoader: "http",
|
||||
langMessagePathForHttpLoader: "src/i18n/lang/",
|
||||
langMessageFileSuffixForHttpLoader: "-lang.json",
|
||||
langMessagePathForHttpLoader: "i18n/lang/",
|
||||
langMessageFileSuffixForHttpLoader: "-lang.json"
|
||||
};
|
||||
|
||||
@NgModule({
|
||||
|
|
|
@ -31,7 +31,8 @@
|
|||
"MORE_INFO": "More info...",
|
||||
"YES": "YES",
|
||||
"NO": "NO",
|
||||
"NEGATIVE": "NEGATIVE"
|
||||
"NEGATIVE": "NEGATIVE",
|
||||
"COPY": "COPY"
|
||||
},
|
||||
"TOOLTIP": {
|
||||
"EMAIL": "Email should be a valid email address like name@example.com.",
|
||||
|
@ -477,7 +478,9 @@
|
|||
},
|
||||
"SINGULAR": "Vulnerability",
|
||||
"PLURAL": "Vulnerabilities",
|
||||
"PLACEHOLDER": "Filter Vulnerabilities"
|
||||
"PLACEHOLDER": "Filter Vulnerabilities",
|
||||
"PACKAGE": "Package with",
|
||||
"PACKAGES": "Packages with"
|
||||
},
|
||||
"PUSH_IMAGE": {
|
||||
"TITLE": "Push Image",
|
||||
|
@ -496,7 +499,8 @@
|
|||
"OS": "OS",
|
||||
"SCAN_COMPLETION_TIME": "Scan Completed",
|
||||
"IMAGE_VULNERABILITIES": "Image Vulnerabilities",
|
||||
"PLACEHOLDER": "We couldn't find any tags!"
|
||||
"PLACEHOLDER": "We couldn't find any tags!",
|
||||
"COPY_ERROR": "Copy failed, please try to manually copy."
|
||||
},
|
||||
"UNKNOWN_ERROR": "Unknown errors have occurred. Please try again later.",
|
||||
"UNAUTHORIZED_ERROR": "Your session is invalid or has expired. You need to sign in to continue your action.",
|
||||
|
|
|
@ -31,7 +31,8 @@
|
|||
"MORE_INFO": "Más información...",
|
||||
"YES": "SI",
|
||||
"NO": "NO",
|
||||
"NEGATIVE": "NEGATIVO"
|
||||
"NEGATIVE": "NEGATIVO",
|
||||
"COPY": "COPY"
|
||||
},
|
||||
"TOOLTIP": {
|
||||
"EMAIL": "El email debe ser una dirección válida como nombre@ejemplo.com.",
|
||||
|
@ -476,7 +477,9 @@
|
|||
},
|
||||
"SINGULAR": "Vulnerability",
|
||||
"PLURAL": "Vulnerabilities",
|
||||
"PLACEHOLDER": "Filter Vulnerabilities"
|
||||
"PLACEHOLDER": "Filter Vulnerabilities",
|
||||
"PACKAGE": "Package with",
|
||||
"PACKAGES": "Packages with"
|
||||
},
|
||||
"PUSH_IMAGE": {
|
||||
"TITLE": "Push Image",
|
||||
|
@ -495,7 +498,8 @@
|
|||
"OS": "OS",
|
||||
"SCAN_COMPLETION_TIME": "Scan Completed",
|
||||
"IMAGE_VULNERABILITIES": "Image Vulnerabilities",
|
||||
"PLACEHOLDER": "We couldn't find any tags!"
|
||||
"PLACEHOLDER": "We couldn't find any tags!",
|
||||
"COPY_ERROR": "Copy failed, please try to manually copy."
|
||||
},
|
||||
"UNKNOWN_ERROR": "Ha ocurrido un error desconocido. Por favor, inténtelo de nuevo más tarde.",
|
||||
"UNAUTHORIZED_ERROR": "La sesión no es válida o ha caducado. Necesita identificarse de nuevo para llevar a cabo esa acción.",
|
||||
|
|
|
@ -31,7 +31,8 @@
|
|||
"MORE_INFO": "更多信息...",
|
||||
"YES": "是",
|
||||
"NO": "否",
|
||||
"NEGATIVE": "否"
|
||||
"NEGATIVE": "否",
|
||||
"COPY": "拷贝"
|
||||
},
|
||||
"TOOLTIP": {
|
||||
"EMAIL": "请使用正确的邮箱地址,比如name@example.com。",
|
||||
|
@ -456,7 +457,7 @@
|
|||
"PLACEHOLDER": "没有扫描结果!",
|
||||
"COLUMN_ID": "缺陷码",
|
||||
"COLUMN_SEVERITY": "严重度",
|
||||
"COLUMN_PACKAGE": "组件",
|
||||
"COLUMN_PACKAGE": "组",
|
||||
"COLUMN_VERSION": "当前版本",
|
||||
"COLUMN_FIXED": "修复版本",
|
||||
"COLUMN_DESCRIPTION": "简介",
|
||||
|
@ -477,7 +478,9 @@
|
|||
},
|
||||
"SINGULAR": "缺陷",
|
||||
"PLURAL": "缺陷",
|
||||
"PLACEHOLDER": "过滤缺陷"
|
||||
"PLACEHOLDER": "过滤缺陷",
|
||||
"PACKAGE": "个组件有",
|
||||
"PACKAGES": "个组件有"
|
||||
},
|
||||
"PUSH_IMAGE": {
|
||||
"TITLE": "推送镜像",
|
||||
|
@ -496,7 +499,8 @@
|
|||
"OS": "操作系统",
|
||||
"SCAN_COMPLETION_TIME": "扫描完成时间",
|
||||
"IMAGE_VULNERABILITIES": "镜像缺陷",
|
||||
"PLACEHOLDER": "未发现任何标签!"
|
||||
"PLACEHOLDER": "未发现任何标签!",
|
||||
"COPY_ERROR": "拷贝失败,请尝试手动拷贝。"
|
||||
},
|
||||
"UNKNOWN_ERROR": "发生未知错误,请稍后再试。",
|
||||
"UNAUTHORIZED_ERROR": "会话无效或者已经过期, 请重新登录以继续。",
|
||||
|
|
Loading…
Reference in New Issue
Block a user