mirror of
https://github.com/goharbor/harbor.git
synced 2025-02-16 20:01:35 +01:00
Update security hub ui (#19062)
1. Fixes #19010 2. Fixes #19011 3. Fixes #19012 4. Fixes #19015 5. Fixes #19025 6. Fixes #19026 7. Fixes #19034 8. Fixes #19037 Signed-off-by: AllForNothing <sshijun@vmware.com>
This commit is contained in:
parent
d93f24a4dc
commit
854e0295d1
@ -29,7 +29,7 @@
|
|||||||
'VULNERABILITY.GRID.COLUMN_SEVERITY' | translate
|
'VULNERABILITY.GRID.COLUMN_SEVERITY' | translate
|
||||||
}}</clr-dg-column>
|
}}</clr-dg-column>
|
||||||
<clr-dg-column class="min-width">{{
|
<clr-dg-column class="min-width">{{
|
||||||
'VULNERABILITY.PACKAGE' | translate
|
'VULNERABILITY.GRID.COLUMN_PACKAGE' | translate
|
||||||
}}</clr-dg-column>
|
}}</clr-dg-column>
|
||||||
<clr-dg-column>{{
|
<clr-dg-column>{{
|
||||||
'VULNERABILITY.GRID.COLUMN_VERSION' | translate
|
'VULNERABILITY.GRID.COLUMN_VERSION' | translate
|
||||||
@ -42,12 +42,17 @@
|
|||||||
</clr-dg-placeholder>
|
</clr-dg-placeholder>
|
||||||
<clr-dg-row *ngFor="let c of vul" [clrDgItem]="c">
|
<clr-dg-row *ngFor="let c of vul" [clrDgItem]="c">
|
||||||
<clr-dg-cell class="min-width">
|
<clr-dg-cell class="min-width">
|
||||||
<span *ngIf="!c?.links || c?.links?.length === 0">{{
|
<span
|
||||||
c.cve_id
|
*ngIf="
|
||||||
}}</span>
|
!c?.links ||
|
||||||
|
c?.links?.length === 0 ||
|
||||||
|
(c?.links?.length === 1 && !c?.links[0])
|
||||||
|
"
|
||||||
|
>{{ c.cve_id }}</span
|
||||||
|
>
|
||||||
<a
|
<a
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
*ngIf="c?.links && c?.links.length === 1"
|
*ngIf="c?.links && c?.links.length === 1 && c?.links[0]"
|
||||||
href="{{ c?.links[0] }}"
|
href="{{ c?.links[0] }}"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>{{ c.cve_id }}</a
|
>{{ c.cve_id }}</a
|
||||||
|
@ -10,12 +10,12 @@ import {
|
|||||||
import { finalize } from 'rxjs/operators';
|
import { finalize } from 'rxjs/operators';
|
||||||
import { VulnerabilityItem } from '../../../../../../ng-swagger-gen/models/vulnerability-item';
|
import { VulnerabilityItem } from '../../../../../../ng-swagger-gen/models/vulnerability-item';
|
||||||
import {
|
import {
|
||||||
|
getDigestLink,
|
||||||
|
getRepoLink,
|
||||||
OptionType,
|
OptionType,
|
||||||
SearchEventData,
|
SearchEventData,
|
||||||
severityText,
|
severityText,
|
||||||
VUL_ID,
|
VUL_ID,
|
||||||
getDigestLink,
|
|
||||||
getRepoLink,
|
|
||||||
} from './security-hub.interface';
|
} from './security-hub.interface';
|
||||||
import { ProjectService } from '../../../../../../ng-swagger-gen/services/project.service';
|
import { ProjectService } from '../../../../../../ng-swagger-gen/services/project.service';
|
||||||
import { VulnerabilityFilterComponent } from './vulnerability-filter/vulnerability-filter.component';
|
import { VulnerabilityFilterComponent } from './vulnerability-filter/vulnerability-filter.component';
|
||||||
@ -96,14 +96,17 @@ export class SecurityHubComponent {
|
|||||||
search(res: SearchEventData) {
|
search(res: SearchEventData) {
|
||||||
if (res?.projectId) {
|
if (res?.projectId) {
|
||||||
this.projectService
|
this.projectService
|
||||||
.getProject({
|
.listProjects({
|
||||||
projectNameOrId: res.projectId,
|
name: res.projectId,
|
||||||
|
page: 1,
|
||||||
|
pageSize: 1,
|
||||||
|
withDetail: false,
|
||||||
})
|
})
|
||||||
.subscribe({
|
.subscribe({
|
||||||
next: project => {
|
next: projects => {
|
||||||
if (project?.project_id) {
|
if (projects?.length) {
|
||||||
res.normal.push(
|
res.normal.push(
|
||||||
`${OptionType.PROJECT_ID}=${project?.project_id}`
|
`${OptionType.PROJECT_ID}=${projects[0]?.project_id}`
|
||||||
);
|
);
|
||||||
this.clrDgRefresh(this.state, res?.normal);
|
this.clrDgRefresh(this.state, res?.normal);
|
||||||
} else {
|
} else {
|
||||||
@ -112,7 +115,8 @@ export class SecurityHubComponent {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
error: err => {
|
error: err => {
|
||||||
this.messageHandler.error(err);
|
res.normal.push(`${OptionType.PROJECT_ID}=0`);
|
||||||
|
this.clrDgRefresh(this.state, res?.normal);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -157,12 +161,30 @@ export class SecurityHubComponent {
|
|||||||
|
|
||||||
searchCVE(cveId: string) {
|
searchCVE(cveId: string) {
|
||||||
this.vulnerabilityFilterComponent.selectedOptions = [OptionType.CVE_ID];
|
this.vulnerabilityFilterComponent.selectedOptions = [OptionType.CVE_ID];
|
||||||
|
this.vulnerabilityFilterComponent.candidates = [
|
||||||
|
OptionType.SEVERITY,
|
||||||
|
OptionType.CVSS3,
|
||||||
|
OptionType.PROJECT_ID,
|
||||||
|
OptionType.REPO,
|
||||||
|
OptionType.PACKAGE,
|
||||||
|
OptionType.TAG,
|
||||||
|
];
|
||||||
|
this.vulnerabilityFilterComponent.valueMap = {};
|
||||||
this.vulnerabilityFilterComponent.valueMap[OptionType.CVE_ID] = cveId;
|
this.vulnerabilityFilterComponent.valueMap[OptionType.CVE_ID] = cveId;
|
||||||
this.currentPage = 1;
|
this.currentPage = 1;
|
||||||
this.clrDgRefresh(this.state, [`${OptionType.CVE_ID}=${cveId}`]);
|
this.clrDgRefresh(this.state, [`${OptionType.CVE_ID}=${cveId}`]);
|
||||||
}
|
}
|
||||||
searchRepo(repoName: string) {
|
searchRepo(repoName: string) {
|
||||||
this.vulnerabilityFilterComponent.selectedOptions = [OptionType.REPO];
|
this.vulnerabilityFilterComponent.selectedOptions = [OptionType.REPO];
|
||||||
|
this.vulnerabilityFilterComponent.candidates = [
|
||||||
|
OptionType.CVE_ID,
|
||||||
|
OptionType.SEVERITY,
|
||||||
|
OptionType.CVSS3,
|
||||||
|
OptionType.PROJECT_ID,
|
||||||
|
OptionType.PACKAGE,
|
||||||
|
OptionType.TAG,
|
||||||
|
];
|
||||||
|
this.vulnerabilityFilterComponent.valueMap = {};
|
||||||
this.vulnerabilityFilterComponent.valueMap[OptionType.REPO] = repoName;
|
this.vulnerabilityFilterComponent.valueMap[OptionType.REPO] = repoName;
|
||||||
this.currentPage = 1;
|
this.currentPage = 1;
|
||||||
this.clrDgRefresh(this.state, [`${OptionType.REPO}=${repoName}`]);
|
this.clrDgRefresh(this.state, [`${OptionType.REPO}=${repoName}`]);
|
||||||
|
@ -29,7 +29,7 @@ export const OptionType_I18n_Map = {
|
|||||||
[OptionType.SEVERITY]: 'VULNERABILITY.GRID.COLUMN_SEVERITY',
|
[OptionType.SEVERITY]: 'VULNERABILITY.GRID.COLUMN_SEVERITY',
|
||||||
[OptionType.CVSS3]: 'VULNERABILITY.GRID.CVSS3',
|
[OptionType.CVSS3]: 'VULNERABILITY.GRID.CVSS3',
|
||||||
[OptionType.REPO]: 'SECURITY_HUB.REPO_NAME',
|
[OptionType.REPO]: 'SECURITY_HUB.REPO_NAME',
|
||||||
[OptionType.PACKAGE]: 'VULNERABILITY.PACKAGE',
|
[OptionType.PACKAGE]: 'VULNERABILITY.GRID.COLUMN_PACKAGE',
|
||||||
[OptionType.TAG]: 'REPLICATION.TAG',
|
[OptionType.TAG]: 'REPLICATION.TAG',
|
||||||
[OptionType.PROJECT_ID]: 'SECURITY_HUB.OPTION_PROJECT_ID_NAME',
|
[OptionType.PROJECT_ID]: 'SECURITY_HUB.OPTION_PROJECT_ID_NAME',
|
||||||
};
|
};
|
||||||
|
@ -56,7 +56,7 @@ export class SingleBarComponent implements OnChanges {
|
|||||||
enabled: true,
|
enabled: true,
|
||||||
distance: -8,
|
distance: -8,
|
||||||
style: {
|
style: {
|
||||||
fontSize: 8,
|
fontSize: '8px',
|
||||||
fontWeight: 1,
|
fontWeight: 1,
|
||||||
},
|
},
|
||||||
pointFormat: '{point.y}',
|
pointFormat: '{point.y}',
|
||||||
|
@ -97,7 +97,7 @@ export class VulnerabilityFilterComponent {
|
|||||||
item === OptionType.PROJECT_ID &&
|
item === OptionType.PROJECT_ID &&
|
||||||
this.valueMap[OptionType.PROJECT_ID]
|
this.valueMap[OptionType.PROJECT_ID]
|
||||||
) {
|
) {
|
||||||
result.projectId = this.valueMap[OptionType.PROJECT_ID];
|
result.projectId = this.valueMap[OptionType.PROJECT_ID]?.trim();
|
||||||
} else if (item === OptionType.SEVERITY) {
|
} else if (item === OptionType.SEVERITY) {
|
||||||
if (this.severity) {
|
if (this.severity) {
|
||||||
result.normal.push(
|
result.normal.push(
|
||||||
@ -108,12 +108,12 @@ export class VulnerabilityFilterComponent {
|
|||||||
if (this.startScore || this.endScore) {
|
if (this.startScore || this.endScore) {
|
||||||
result.normal.push(
|
result.normal.push(
|
||||||
`${OptionType.CVSS3}=[${
|
`${OptionType.CVSS3}=[${
|
||||||
this.startScore ? this.startScore : '0.0'
|
this.startScore ? this.startScore?.trim() : '0.0'
|
||||||
}~${this.endScore ? this.endScore : '10.0'}]`
|
}~${this.endScore ? this.endScore?.trim() : '10.0'}]`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else if (this.valueMap[item]) {
|
} else if (this.valueMap[item]) {
|
||||||
result.normal.push(`${item}=${this.valueMap[item]}`);
|
result.normal.push(`${item}=${this.valueMap[item]?.trim()}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.search.emit(result);
|
this.search.emit(result);
|
||||||
|
@ -116,16 +116,18 @@
|
|||||||
<div
|
<div
|
||||||
class="clr-row row"
|
class="clr-row row"
|
||||||
*ngFor="let item of securitySummary?.dangerous_artifacts">
|
*ngFor="let item of securitySummary?.dangerous_artifacts">
|
||||||
<div class="clr-col ellipsis">
|
<div class="clr-col">
|
||||||
<a
|
<a
|
||||||
class="search"
|
class="search"
|
||||||
href="javascript:void(0)"
|
href="javascript:void(0)"
|
||||||
appScrollAnchor="{{ vulId }}"
|
appScrollAnchor="{{ vulId }}"
|
||||||
(click)="searchRepoClick(item?.repository_name)"
|
(click)="searchRepoClick(item?.repository_name)"
|
||||||
title="{{ item.repository_name }}"
|
title="{{ item.repository_name }}">
|
||||||
><clr-icon shape="search"></clr-icon
|
<span class="ellipsis">
|
||||||
>{{ item.repository_name }}</a
|
<clr-icon shape="search"></clr-icon
|
||||||
>
|
>{{ item.repository_name }}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="clr-col" title="{{ item?.digest }}">
|
<div class="clr-col" title="{{ item?.digest }}">
|
||||||
<a
|
<a
|
||||||
@ -137,8 +139,10 @@
|
|||||||
item.digest
|
item.digest
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
>{{ item?.digest?.slice(0, 15) }}</a
|
><span class="ellipsis">{{
|
||||||
>
|
item?.digest?.slice(0, 15)
|
||||||
|
}}</span>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="clr-col">
|
<div class="clr-col">
|
||||||
<div class="single-bar-container">
|
<div class="single-bar-container">
|
||||||
@ -163,7 +167,7 @@
|
|||||||
{{ 'VULNERABILITY.GRID.CVSS3' | translate }}
|
{{ 'VULNERABILITY.GRID.CVSS3' | translate }}
|
||||||
</div>
|
</div>
|
||||||
<div class="clr-col-4 column">
|
<div class="clr-col-4 column">
|
||||||
{{ 'VULNERABILITY.PACKAGE' | translate }}
|
{{ 'VULNERABILITY.GRID.COLUMN_PACKAGE' | translate }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -171,16 +175,18 @@
|
|||||||
<div
|
<div
|
||||||
class="clr-row row"
|
class="clr-row row"
|
||||||
*ngFor="let item of securitySummary?.dangerous_cves">
|
*ngFor="let item of securitySummary?.dangerous_cves">
|
||||||
<div class="clr-col-4 ellipsis">
|
<div class="clr-col-4">
|
||||||
<a
|
<a
|
||||||
class="search"
|
class="search"
|
||||||
href="javascript:void(0)"
|
href="javascript:void(0)"
|
||||||
appScrollAnchor="{{ vulId }}"
|
appScrollAnchor="{{ vulId }}"
|
||||||
(click)="searchCVEClick(item?.cve_id)"
|
(click)="searchCVEClick(item?.cve_id)"
|
||||||
title="{{ item.cve_id }}"
|
title="{{ item.cve_id }}">
|
||||||
><clr-icon shape="search"></clr-icon
|
<span class="ellipsis">
|
||||||
>{{ item.cve_id }}</a
|
<clr-icon shape="search"></clr-icon
|
||||||
>
|
>{{ item.cve_id }}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="clr-col-2">
|
<div class="clr-col-2">
|
||||||
<ng-container [ngSwitch]="item.severity">
|
<ng-container [ngSwitch]="item.severity">
|
||||||
|
@ -113,6 +113,7 @@ export class VulnerabilitySummaryComponent implements OnInit, OnDestroy {
|
|||||||
enabled: false,
|
enabled: false,
|
||||||
},
|
},
|
||||||
showInLegend: true,
|
showInLegend: true,
|
||||||
|
borderWidth: 0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { throwError as observableThrowError, Observable, of } from 'rxjs';
|
import { throwError as observableThrowError, Observable, of } from 'rxjs';
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { HttpClient, HttpParams, HttpResponse } from '@angular/common/http';
|
import { HttpClient, HttpParams, HttpResponse } from '@angular/common/http';
|
||||||
import { catchError } from 'rxjs/operators';
|
import { catchError, share } from 'rxjs/operators';
|
||||||
import { Project } from '../../base/project/project-config/project-policy-config/project';
|
import { Project } from '../../base/project/project-config/project-policy-config/project';
|
||||||
import { ProjectPolicy } from '../../base/project/project-config/project-policy-config/project-policy-config.component';
|
import { ProjectPolicy } from '../../base/project/project-config/project-policy-config/project-policy-config.component';
|
||||||
import {
|
import {
|
||||||
@ -10,6 +10,7 @@ import {
|
|||||||
buildHttpRequestOptionsWithObserveResponse,
|
buildHttpRequestOptionsWithObserveResponse,
|
||||||
CURRENT_BASE_HREF,
|
CURRENT_BASE_HREF,
|
||||||
} from '../units/utils';
|
} from '../units/utils';
|
||||||
|
import { CacheObservable } from '../units/cache-util';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define the service methods to handle the Project related things.
|
* Define the service methods to handle the Project related things.
|
||||||
@ -87,18 +88,26 @@ export abstract class ProjectService {
|
|||||||
*/
|
*/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ProjectDefaultService extends ProjectService {
|
export class ProjectDefaultService extends ProjectService {
|
||||||
|
// to avoid multiple requests for one navigating action
|
||||||
|
private _sharedProjectObservableMap: {
|
||||||
|
[key: number | string]: Observable<Project>;
|
||||||
|
} = {};
|
||||||
constructor(private http: HttpClient) {
|
constructor(private http: HttpClient) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
@CacheObservable({ maxAge: 1000 * 60 })
|
||||||
public getProject(projectId: number | string): Observable<Project> {
|
public getProject(projectId: number | string): Observable<Project> {
|
||||||
if (!projectId) {
|
if (!projectId) {
|
||||||
return observableThrowError('Bad argument');
|
return observableThrowError('Bad argument');
|
||||||
}
|
}
|
||||||
let baseUrl: string = CURRENT_BASE_HREF + '/projects';
|
let baseUrl: string = CURRENT_BASE_HREF + '/projects';
|
||||||
return this.http
|
if (this._sharedProjectObservableMap[projectId]) {
|
||||||
|
return this._sharedProjectObservableMap[projectId];
|
||||||
|
}
|
||||||
|
this._sharedProjectObservableMap[projectId] = this.http
|
||||||
.get<Project>(`${baseUrl}/${projectId}`, HTTP_GET_OPTIONS)
|
.get<Project>(`${baseUrl}/${projectId}`, HTTP_GET_OPTIONS)
|
||||||
.pipe(catchError(error => observableThrowError(error)));
|
.pipe(share());
|
||||||
|
return this._sharedProjectObservableMap[projectId];
|
||||||
}
|
}
|
||||||
|
|
||||||
public updateProjectPolicy(
|
public updateProjectPolicy(
|
||||||
|
@ -1886,7 +1886,7 @@
|
|||||||
"CVE": "CVEs",
|
"CVE": "CVEs",
|
||||||
"FILTER_BY": "Filter by",
|
"FILTER_BY": "Filter by",
|
||||||
"OPTION_ALL": "All",
|
"OPTION_ALL": "All",
|
||||||
"OPTION_PROJECT_ID_NAME": "Project id or name",
|
"OPTION_PROJECT_ID_NAME": "Project Name",
|
||||||
"SEARCH": "SEARCH",
|
"SEARCH": "SEARCH",
|
||||||
"REPO_NAME": "Repository Name",
|
"REPO_NAME": "Repository Name",
|
||||||
"TOOLTIP": "All filters except CVSS3 only support exact matches",
|
"TOOLTIP": "All filters except CVSS3 only support exact matches",
|
||||||
|
@ -1887,7 +1887,7 @@
|
|||||||
"CVE": "CVEs",
|
"CVE": "CVEs",
|
||||||
"FILTER_BY": "Filter by",
|
"FILTER_BY": "Filter by",
|
||||||
"OPTION_ALL": "All",
|
"OPTION_ALL": "All",
|
||||||
"OPTION_PROJECT_ID_NAME": "Project Id or Name",
|
"OPTION_PROJECT_ID_NAME": "Project Name",
|
||||||
"SEARCH": "SEARCH",
|
"SEARCH": "SEARCH",
|
||||||
"REPO_NAME": "Repository Name",
|
"REPO_NAME": "Repository Name",
|
||||||
"TOOLTIP": "All filters except CVSS3 only support exact matches",
|
"TOOLTIP": "All filters except CVSS3 only support exact matches",
|
||||||
|
@ -1883,7 +1883,7 @@
|
|||||||
"CVE": "CVEs",
|
"CVE": "CVEs",
|
||||||
"FILTER_BY": "Filter by",
|
"FILTER_BY": "Filter by",
|
||||||
"OPTION_ALL": "All",
|
"OPTION_ALL": "All",
|
||||||
"OPTION_PROJECT_ID_NAME": "Project id or name",
|
"OPTION_PROJECT_ID_NAME": "Project Name",
|
||||||
"SEARCH": "SEARCH",
|
"SEARCH": "SEARCH",
|
||||||
"REPO_NAME": "Repository Name",
|
"REPO_NAME": "Repository Name",
|
||||||
"TOOLTIP": "All filters except CVSS3 only support exact matches",
|
"TOOLTIP": "All filters except CVSS3 only support exact matches",
|
||||||
|
@ -1853,7 +1853,7 @@
|
|||||||
"CVE": "CVEs",
|
"CVE": "CVEs",
|
||||||
"FILTER_BY": "Filter by",
|
"FILTER_BY": "Filter by",
|
||||||
"OPTION_ALL": "All",
|
"OPTION_ALL": "All",
|
||||||
"OPTION_PROJECT_ID_NAME": "Project id or name",
|
"OPTION_PROJECT_ID_NAME": "Project Name",
|
||||||
"SEARCH": "SEARCH",
|
"SEARCH": "SEARCH",
|
||||||
"REPO_NAME": "Repository Name",
|
"REPO_NAME": "Repository Name",
|
||||||
"TOOLTIP": "All filters except CVSS3 only support exact matches",
|
"TOOLTIP": "All filters except CVSS3 only support exact matches",
|
||||||
|
@ -1883,7 +1883,7 @@
|
|||||||
"CVE": "CVEs",
|
"CVE": "CVEs",
|
||||||
"FILTER_BY": "Filter by",
|
"FILTER_BY": "Filter by",
|
||||||
"OPTION_ALL": "All",
|
"OPTION_ALL": "All",
|
||||||
"OPTION_PROJECT_ID_NAME": "Project id or name",
|
"OPTION_PROJECT_ID_NAME": "Project Name",
|
||||||
"SEARCH": "SEARCH",
|
"SEARCH": "SEARCH",
|
||||||
"REPO_NAME": "Repository Name",
|
"REPO_NAME": "Repository Name",
|
||||||
"TOOLTIP": "All filters except CVSS3 only support exact matches",
|
"TOOLTIP": "All filters except CVSS3 only support exact matches",
|
||||||
|
@ -1886,7 +1886,7 @@
|
|||||||
"CVE": "CVEs",
|
"CVE": "CVEs",
|
||||||
"FILTER_BY": "Filter by",
|
"FILTER_BY": "Filter by",
|
||||||
"OPTION_ALL": "All",
|
"OPTION_ALL": "All",
|
||||||
"OPTION_PROJECT_ID_NAME": "Project id or name",
|
"OPTION_PROJECT_ID_NAME": "Project Name",
|
||||||
"SEARCH": "SEARCH",
|
"SEARCH": "SEARCH",
|
||||||
"REPO_NAME": "Repository Name",
|
"REPO_NAME": "Repository Name",
|
||||||
"TOOLTIP": "All filters except CVSS3 only support exact matches",
|
"TOOLTIP": "All filters except CVSS3 only support exact matches",
|
||||||
|
@ -1883,7 +1883,7 @@
|
|||||||
"CVE": "CVEs",
|
"CVE": "CVEs",
|
||||||
"FILTER_BY": "过滤条件",
|
"FILTER_BY": "过滤条件",
|
||||||
"OPTION_ALL": "全部",
|
"OPTION_ALL": "全部",
|
||||||
"OPTION_PROJECT_ID_NAME": "项目 ID 或 名称",
|
"OPTION_PROJECT_ID_NAME": "项目名称",
|
||||||
"SEARCH": "搜索",
|
"SEARCH": "搜索",
|
||||||
"REPO_NAME": "仓库名称",
|
"REPO_NAME": "仓库名称",
|
||||||
"TOOLTIP": "CVSS3 除外的所有过滤项只支持精确匹配",
|
"TOOLTIP": "CVSS3 除外的所有过滤项只支持精确匹配",
|
||||||
|
@ -1875,7 +1875,7 @@
|
|||||||
"CVE": "CVEs",
|
"CVE": "CVEs",
|
||||||
"FILTER_BY": "Filter by",
|
"FILTER_BY": "Filter by",
|
||||||
"OPTION_ALL": "All",
|
"OPTION_ALL": "All",
|
||||||
"OPTION_PROJECT_ID_NAME": "Project id or name",
|
"OPTION_PROJECT_ID_NAME": "Project Name",
|
||||||
"SEARCH": "SEARCH",
|
"SEARCH": "SEARCH",
|
||||||
"REPO_NAME": "Repository Name",
|
"REPO_NAME": "Repository Name",
|
||||||
"TOOLTIP": "All filters except CVSS3 only support exact matches",
|
"TOOLTIP": "All filters except CVSS3 only support exact matches",
|
||||||
|
Loading…
Reference in New Issue
Block a user