From eca3d82d9cfb193b88592496836aec56cb0190d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=99=E4=B8=96=E5=86=9B?= <30999793+AllForNothing@users.noreply.github.com> Date: Tue, 24 Aug 2021 17:04:37 +0800 Subject: [PATCH] Improve global search component (#15462) Signed-off-by: AllForNothing --- .../global-search.component.html | 4 +- .../global-search/global-search.component.ts | 51 ++++++++---- .../list-chart-version-ro.component.html | 2 +- .../list-chart-version-ro.component.ts | 7 +- .../list-project-ro.component.html | 7 +- .../list-project-ro.component.spec.ts | 77 +++++++++++-------- .../list-project-ro.component.ts | 36 +++------ .../list-repository-ro.component.html | 7 +- .../list-repository-ro.component.ts | 67 ++++------------ src/portal/src/i18n/lang/de-de-lang.json | 3 +- src/portal/src/i18n/lang/en-us-lang.json | 3 +- src/portal/src/i18n/lang/es-es-lang.json | 3 +- src/portal/src/i18n/lang/fr-fr-lang.json | 3 +- src/portal/src/i18n/lang/pt-br-lang.json | 3 +- src/portal/src/i18n/lang/tr-tr-lang.json | 3 +- src/portal/src/i18n/lang/zh-cn-lang.json | 3 +- src/portal/src/i18n/lang/zh-tw-lang.json | 3 +- 17 files changed, 135 insertions(+), 147 deletions(-) diff --git a/src/portal/src/app/shared/components/global-search/global-search.component.html b/src/portal/src/app/shared/components/global-search/global-search.component.html index d6848dd47..ee1ff5925 100644 --- a/src/portal/src/app/shared/components/global-search/global-search.component.html +++ b/src/portal/src/app/shared/components/global-search/global-search.component.html @@ -1,5 +1,5 @@ \ No newline at end of file + diff --git a/src/portal/src/app/shared/components/global-search/global-search.component.ts b/src/portal/src/app/shared/components/global-search/global-search.component.ts index 9abcb45bc..c889a1bf9 100644 --- a/src/portal/src/app/shared/components/global-search/global-search.component.ts +++ b/src/portal/src/app/shared/components/global-search/global-search.component.ts @@ -1,4 +1,3 @@ - import { debounceTime, distinctUntilChanged } from 'rxjs/operators'; // Copyright (c) 2017 VMware, Inc. All Rights Reserved. // @@ -13,20 +12,17 @@ import { debounceTime, distinctUntilChanged } from 'rxjs/operators'; // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -import { Component, OnInit, OnDestroy } from '@angular/core'; -import { Router } from '@angular/router'; -import { Subject , Subscription } from "rxjs"; - +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { Subject, Subscription } from "rxjs"; import { SearchTriggerService } from './search-trigger.service'; - import { AppConfigService } from '../../../services/app-config.service'; - - - -import {TranslateService} from "@ngx-translate/core"; -import {SkinableConfig} from "../../../services/skinable-config.service"; +import { TranslateService } from "@ngx-translate/core"; +import { SkinableConfig } from "../../../services/skinable-config.service"; +import { Location } from '@angular/common'; const deBounceTime = 500; // ms +const SEARCH_KEY: string = 'globalSearch'; @Component({ selector: 'global-search', @@ -43,13 +39,13 @@ export class GlobalSearchComponent implements OnInit, OnDestroy { // To indicate if the result panel is opened isResPanelOpened: boolean = false; - searchTerm: string = ""; - placeholderText: string; - + private _searchTerm = ""; constructor( private searchTrigger: SearchTriggerService, private router: Router, + private activatedRoute: ActivatedRoute, + private location: Location, private appConfigService: AppConfigService, private translate: TranslateService, private skinableConfig: SkinableConfig) { @@ -71,8 +67,7 @@ export class GlobalSearchComponent implements OnInit, OnDestroy { } this.searchSub = this.searchTerms.pipe( - debounceTime(deBounceTime), - distinctUntilChanged()) + debounceTime(deBounceTime)) .subscribe(term => { this.searchTrigger.triggerSearch(term); }); @@ -83,6 +78,11 @@ export class GlobalSearchComponent implements OnInit, OnDestroy { if (this.appConfigService.isIntegrationMode()) { this.placeholderText = "GLOBAL_SEARCH.PLACEHOLDER_VIC"; } + // init _searchTerm from queryParams + this._searchTerm = this.activatedRoute.snapshot.queryParams[SEARCH_KEY]; + if (this._searchTerm) { + this.searchTerms.next(this._searchTerm); + } } ngOnDestroy(): void { @@ -98,7 +98,24 @@ export class GlobalSearchComponent implements OnInit, OnDestroy { // Handle the term inputting event search(term: string): void { // Send event even term is empty - this.searchTerms.next(term.trim()); } + get searchTerm(): string { + return this._searchTerm; + } + set searchTerm(s) { + let url: string; + if (s) { + url = this.router.createUrlTree([], { + relativeTo: this.activatedRoute, + queryParams: {[SEARCH_KEY]: s} + }).toString(); + } else { + url = this.router.createUrlTree([], { + relativeTo: this.activatedRoute, + }).toString(); + } + this.location.replaceState(url); + this._searchTerm = s; + } } diff --git a/src/portal/src/app/shared/components/list-chart-version-ro/list-chart-version-ro.component.html b/src/portal/src/app/shared/components/list-chart-version-ro/list-chart-version-ro.component.html index 114be4d71..d708fb4f5 100644 --- a/src/portal/src/app/shared/components/list-chart-version-ro/list-chart-version-ro.component.html +++ b/src/portal/src/app/shared/components/list-chart-version-ro/list-chart-version-ro.component.html @@ -22,4 +22,4 @@ {{charts?.length}} {{'HELM_CHART.ITEMS'| translate}} - \ No newline at end of file + diff --git a/src/portal/src/app/shared/components/list-chart-version-ro/list-chart-version-ro.component.ts b/src/portal/src/app/shared/components/list-chart-version-ro/list-chart-version-ro.component.ts index 2c0256809..0c6ff6714 100644 --- a/src/portal/src/app/shared/components/list-chart-version-ro/list-chart-version-ro.component.ts +++ b/src/portal/src/app/shared/components/list-chart-version-ro/list-chart-version-ro.component.ts @@ -1,5 +1,5 @@ import { Router } from '@angular/router'; -import { Component, OnInit, Input } from '@angular/core'; +import { Component, OnInit, Input, ChangeDetectionStrategy } from '@angular/core'; import { HelmChartSearchResultItem, HelmChartVersion, HelmChartMaintainer } from '../../../base/project/helm-chart/helm-chart-detail/helm-chart.interface.service'; import { SearchTriggerService } from '../global-search/search-trigger.service'; import { ProjectService } from "../../services"; @@ -7,11 +7,10 @@ import { ProjectService } from "../../services"; @Component({ selector: 'list-chart-version-ro', - templateUrl: './list-chart-version-ro.component.html' + templateUrl: './list-chart-version-ro.component.html', + changeDetection: ChangeDetectionStrategy.OnPush }) export class ListChartVersionRoComponent implements OnInit { - - @Input() projectId: number; @Input() charts: HelmChartSearchResultItem[]; constructor( diff --git a/src/portal/src/app/shared/components/list-project-ro/list-project-ro.component.html b/src/portal/src/app/shared/components/list-project-ro/list-project-ro.component.html index 1fda4aee0..38b0c3a26 100644 --- a/src/portal/src/app/shared/components/list-project-ro/list-project-ro.component.html +++ b/src/portal/src/app/shared/components/list-project-ro/list-project-ro.component.html @@ -1,16 +1,17 @@ - + {{'PROJECT.NAME' | translate}} {{'PROJECT.ACCESS_LEVEL' | translate}} {{'PROJECT.REPO_COUNT'| translate}} {{'PROJECT.CREATION_TIME' | translate}} - {{p.name}} + {{p.name}} {{ (p.metadata.public === 'true' ? 'PROJECT.PUBLIC' : 'PROJECT.PRIVATE') | translate}} {{p.repo_count}} {{p.creation_time | harborDatetime: 'short'}} + {{'PROJECT.NO_PROJECT' | translate }} {{pagination.firstItem + 1}} - {{pagination.lastItem +1 }} {{'PROJECT.OF' | translate}} {{projects?.length}} {{'PROJECT.ITEMS' | translate}} - \ No newline at end of file + diff --git a/src/portal/src/app/shared/components/list-project-ro/list-project-ro.component.spec.ts b/src/portal/src/app/shared/components/list-project-ro/list-project-ro.component.spec.ts index 451e65e97..20f87392e 100644 --- a/src/portal/src/app/shared/components/list-project-ro/list-project-ro.component.spec.ts +++ b/src/portal/src/app/shared/components/list-project-ro/list-project-ro.component.spec.ts @@ -1,47 +1,50 @@ import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing'; -import { TranslateModule, TranslateService } from '@ngx-translate/core'; import { ListProjectROComponent } from './list-project-ro.component'; -import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; -import { BrowserAnimationsModule, NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { ClarityModule } from '@clr/angular'; -import { FormsModule } from '@angular/forms'; -import { RouterTestingModule } from '@angular/router/testing'; -import { of } from 'rxjs'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { SearchTriggerService } from '../global-search/search-trigger.service'; +import { SharedTestingModule } from "../../shared.module"; +import { Project } from "../../../../../ng-swagger-gen/models/project"; +import { Component } from '@angular/core'; + +// mock a TestHostComponent for ListProjectROComponent +@Component({ + template: ` + + ` +}) +class TestHostComponent { + projects: Project[] = []; +} describe('ListProjectROComponent', () => { - let component: ListProjectROComponent; - let fixture: ComponentFixture; - const mockSearchTriggerService = { - closeSearch: () => { } - }; + let component: TestHostComponent; + let fixture: ComponentFixture; + const mockedProjects: Project[] = [ + { + chart_count: 0, + name: "test1", + metadata: {}, + project_id: 1, + repo_count: 1 + }, + { + chart_count: 0, + name: "test2", + metadata: {}, + project_id: 2, + repo_count: 1 + } + ]; beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ - schemas: [ - CUSTOM_ELEMENTS_SCHEMA - ], imports: [ - BrowserAnimationsModule, - ClarityModule, - TranslateModule.forRoot(), - FormsModule, - RouterTestingModule, - NoopAnimationsModule, - HttpClientTestingModule + SharedTestingModule ], - declarations: [ListProjectROComponent], - providers: [ - TranslateService, - { provide: SearchTriggerService, useValue: mockSearchTriggerService } - - ] - }) - .compileComponents(); + declarations: [ListProjectROComponent, + TestHostComponent], + }).compileComponents(); })); beforeEach(() => { - fixture = TestBed.createComponent(ListProjectROComponent); + fixture = TestBed.createComponent(TestHostComponent); component = fixture.componentInstance; fixture.detectChanges(); }); @@ -49,4 +52,12 @@ describe('ListProjectROComponent', () => { it('should create', () => { expect(component).toBeTruthy(); }); + + it('should render project list', async () => { + component.projects = mockedProjects; + fixture.detectChanges(); + await fixture.whenStable(); + const rows = fixture.nativeElement.querySelectorAll('clr-dg-row'); + expect(rows.length).toEqual(2); + }); }); diff --git a/src/portal/src/app/shared/components/list-project-ro/list-project-ro.component.ts b/src/portal/src/app/shared/components/list-project-ro/list-project-ro.component.ts index 652eda1f5..75cb2a6ba 100644 --- a/src/portal/src/app/shared/components/list-project-ro/list-project-ro.component.ts +++ b/src/portal/src/app/shared/components/list-project-ro/list-project-ro.component.ts @@ -11,35 +11,21 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -import { Component, EventEmitter, Output, Input, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; -import { Router } from '@angular/router'; -import { State } from '../../services/interface'; - -import { SearchTriggerService } from '../global-search/search-trigger.service'; -import { Project } from '../../../base/project/project'; +import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; +import { Project } from "../../../../../ng-swagger-gen/models/project"; @Component({ - selector: 'list-project-ro', - templateUrl: 'list-project-ro.component.html', - changeDetection: ChangeDetectionStrategy.OnPush + selector: 'list-project-ro', + templateUrl: 'list-project-ro.component.html', + changeDetection: ChangeDetectionStrategy.OnPush }) export class ListProjectROComponent { - @Input() projects: Project[]; - @Output() paginate = new EventEmitter(); + @Input() projects: Project[]; + constructor() { + } - constructor( - private searchTrigger: SearchTriggerService, - private router: Router) {} - - goToLink(proId: number): void { - this.searchTrigger.closeSearch(true); - - let linkUrl = ['harbor', 'projects', proId, 'repositories']; - this.router.navigate(linkUrl); - } - - refresh(state: State) { - this.paginate.emit(state); - } + getLink(proId: number) { + return `/harbor/projects/${proId}/repositories`; + } } diff --git a/src/portal/src/app/shared/components/list-repository-ro/list-repository-ro.component.html b/src/portal/src/app/shared/components/list-repository-ro/list-repository-ro.component.html index 03705da80..84964ca0d 100644 --- a/src/portal/src/app/shared/components/list-repository-ro/list-repository-ro.component.html +++ b/src/portal/src/app/shared/components/list-repository-ro/list-repository-ro.component.html @@ -1,14 +1,15 @@ - + {{'REPOSITORY.NAME' | translate}} {{'REPOSITORY.ARTIFACTS_COUNT' | translate}} {{'REPOSITORY.PULL_COUNT' | translate}} - {{r.name || r.repository_name}} + {{r.name || r.repository_name}} {{r.artifact_count}} {{r.pull_count}} + {{'REPOSITORY.PLACEHOLDER' | translate }} {{pagination.firstItem + 1}} - {{pagination.lastItem +1 }} {{'REPOSITORY.OF' | translate}} {{repositories?.length }} {{'REPOSITORY.ITEMS' | translate}} - \ No newline at end of file + diff --git a/src/portal/src/app/shared/components/list-repository-ro/list-repository-ro.component.ts b/src/portal/src/app/shared/components/list-repository-ro/list-repository-ro.component.ts index 1e6628bcf..bb045b8c0 100644 --- a/src/portal/src/app/shared/components/list-repository-ro/list-repository-ro.component.ts +++ b/src/portal/src/app/shared/components/list-repository-ro/list-repository-ro.component.ts @@ -1,5 +1,3 @@ - -import {filter} from 'rxjs/operators'; // Copyright (c) 2017 VMware, Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,72 +11,39 @@ import {filter} from 'rxjs/operators'; // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -import { Component, Input, Output, OnDestroy, EventEmitter, ChangeDetectionStrategy, ChangeDetectorRef, OnInit } from '@angular/core'; -import { Router, NavigationEnd } from '@angular/router'; -import { State } from '../../services/interface'; +import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; +import { Router } from '@angular/router'; import { Repository } from '../../../../../ng-swagger-gen/models/repository'; - import { SearchTriggerService } from '../global-search/search-trigger.service'; -import {Subscription} from "rxjs"; import { SessionService } from "../../services/session.service"; import { UN_LOGGED_PARAM } from "../../../account/sign-in/sign-in.service"; + const YES: string = 'yes'; + @Component({ selector: 'list-repository-ro', templateUrl: 'list-repository-ro.component.html', changeDetection: ChangeDetectionStrategy.OnPush }) -export class ListRepositoryROComponent implements OnInit, OnDestroy { +export class ListRepositoryROComponent { - @Input() projectId: number; @Input() repositories: Repository[]; - @Output() paginate = new EventEmitter(); - - routerSubscription: Subscription; - constructor( - private router: Router, - private searchTrigger: SearchTriggerService, - private ref: ChangeDetectorRef, - private sessionService: SessionService) { - this.router.routeReuseStrategy.shouldReuseRoute = function() { - return false; - }; - this.routerSubscription = this.router.events.pipe(filter(event => event instanceof NavigationEnd)) - .subscribe((event) => { - // trick the Router into believing it's last link wasn't previously loaded - this.router.navigated = false; - // if you need to scroll back to top, here is the right place - window.scrollTo(0, 0); - }); + private router: Router, + private searchTrigger: SearchTriggerService, + private sessionService: SessionService) { } - ngOnInit(): void { - let hnd = setInterval(() => this.ref.markForCheck(), 100); - setTimeout(() => clearInterval(hnd), 1000); - } - - ngOnDestroy(): void { - this.routerSubscription.unsubscribe(); - } - - refresh(state: State) { - if (this.repositories) { - this.paginate.emit(state); - } - } - - public gotoLink(projectId: number, repoName: string): void { - this.searchTrigger.closeSearch(true); + getLink(projectId: number, repoName: string) { let projectName = repoName.split('/')[0]; let repositorieName = projectName ? repoName.substr(projectName.length + 1) : repoName; - let linkUrl = ['harbor', 'projects', projectId, 'repositories', repositorieName ]; - if (this.sessionService.getCurrentUser()) { - this.router.navigate(linkUrl); - } else {// if not logged in and it's a public project, add param 'publicAndNotLogged' - this.router.navigate(linkUrl, {queryParams: {[UN_LOGGED_PARAM]: YES}}); - } + return `/harbor/projects/${projectId}/repositories/${repositorieName}`; + } + getQueryParams() { + if (this.sessionService.getCurrentUser()) { + return null; + } + return {[UN_LOGGED_PARAM]: YES}; } - } diff --git a/src/portal/src/i18n/lang/de-de-lang.json b/src/portal/src/i18n/lang/de-de-lang.json index dc45adb4f..267cb1c89 100644 --- a/src/portal/src/i18n/lang/de-de-lang.json +++ b/src/portal/src/i18n/lang/de-de-lang.json @@ -254,7 +254,8 @@ "PROXY_CACHE": "Proxy Cache", "PROXY_CACHE_TOOLTIP": "Die Aktivierung der Funktion erlaubt es dem Projekt, als Cache für eine andere Registry Instanz zu dienen. Harbor unterstützt die Proxy Funktion nur für DockerHub, Docker Registry, Harbor, Aws ECR, Azure ACR, Quay und Google GCR.", "ENDPOINT": "Endpunkt", - "PROXY_CACHE_ENDPOINT": "Proxy Cache Endpunkt" + "PROXY_CACHE_ENDPOINT": "Proxy Cache Endpunkt", + "NO_PROJECT": "We couldn't find any projects" }, "PROJECT_DETAIL": { "SUMMARY": "Zusammenfassung", diff --git a/src/portal/src/i18n/lang/en-us-lang.json b/src/portal/src/i18n/lang/en-us-lang.json index 43f6e46f6..a9c8e44da 100644 --- a/src/portal/src/i18n/lang/en-us-lang.json +++ b/src/portal/src/i18n/lang/en-us-lang.json @@ -254,7 +254,8 @@ "PROXY_CACHE": "Proxy Cache", "PROXY_CACHE_TOOLTIP": "Enable this to allow this project to act as a pull-through cache for a particular target registry instance. Harbor can only act a proxy for DockerHub, Docker Registry, Harbor, Aws ECR, Azure ACR, Quay and Google GCR registries.", "ENDPOINT": "Endpoint", - "PROXY_CACHE_ENDPOINT": "Proxy Cache Endpoint" + "PROXY_CACHE_ENDPOINT": "Proxy Cache Endpoint", + "NO_PROJECT": "We couldn't find any projects" }, "PROJECT_DETAIL": { "SUMMARY": "Summary", diff --git a/src/portal/src/i18n/lang/es-es-lang.json b/src/portal/src/i18n/lang/es-es-lang.json index 47e213db3..b31f2a647 100644 --- a/src/portal/src/i18n/lang/es-es-lang.json +++ b/src/portal/src/i18n/lang/es-es-lang.json @@ -255,7 +255,8 @@ "PROXY_CACHE": "Proxy Cache", "PROXY_CACHE_TOOLTIP": "Enable this to allow this project to act as a pull-through cache for a particular target registry instance. Harbor can only act a proxy for DockerHub, Docker Registry, Harbor, Aws ECR, Azure ACR, Quay and Google GCR registries.", "ENDPOINT": "Endpoint", - "PROXY_CACHE_ENDPOINT": "Proxy Cache Endpoint" + "PROXY_CACHE_ENDPOINT": "Proxy Cache Endpoint", + "NO_PROJECT": "We couldn't find any projects" }, "PROJECT_DETAIL": { "SUMMARY": "Summary", diff --git a/src/portal/src/i18n/lang/fr-fr-lang.json b/src/portal/src/i18n/lang/fr-fr-lang.json index 9bee5f2d0..5f8e508da 100644 --- a/src/portal/src/i18n/lang/fr-fr-lang.json +++ b/src/portal/src/i18n/lang/fr-fr-lang.json @@ -248,7 +248,8 @@ "PROXY_CACHE": "Proxy Cache", "PROXY_CACHE_TOOLTIP": "Enable this to allow this project to act as a pull-through cache for a particular target registry instance. Harbor can only act a proxy for DockerHub, Docker Registry, Harbor, Aws ECR, Azure ACR, Quay and Google GCR registries.", "ENDPOINT": "Endpoint", - "PROXY_CACHE_ENDPOINT": "Proxy Cache Endpoint" + "PROXY_CACHE_ENDPOINT": "Proxy Cache Endpoint", + "NO_PROJECT": "We couldn't find any projects" }, "PROJECT_DETAIL": { "SUMMARY": "Summary", diff --git a/src/portal/src/i18n/lang/pt-br-lang.json b/src/portal/src/i18n/lang/pt-br-lang.json index 8bd6f59e6..4060daee1 100644 --- a/src/portal/src/i18n/lang/pt-br-lang.json +++ b/src/portal/src/i18n/lang/pt-br-lang.json @@ -252,7 +252,8 @@ "PROXY_CACHE": "Proxy Cache", "PROXY_CACHE_TOOLTIP": "Enable this to allow this project to act as a pull-through cache for a particular target registry instance. Harbor can only act a proxy for DockerHub, Docker Registry, Harbor, Aws ECR, Azure ACR, Quay and Google GCR registries.", "ENDPOINT": "Endpoint", - "PROXY_CACHE_ENDPOINT": "Proxy Cache Endpoint" + "PROXY_CACHE_ENDPOINT": "Proxy Cache Endpoint", + "NO_PROJECT": "We couldn't find any projects" }, "PROJECT_DETAIL": { "SUMMARY": "Summary", diff --git a/src/portal/src/i18n/lang/tr-tr-lang.json b/src/portal/src/i18n/lang/tr-tr-lang.json index 07a6f1b42..65ec8514f 100644 --- a/src/portal/src/i18n/lang/tr-tr-lang.json +++ b/src/portal/src/i18n/lang/tr-tr-lang.json @@ -254,7 +254,8 @@ "PROXY_CACHE": "Proxy Cache", "PROXY_CACHE_TOOLTIP": "Enable this to allow this project to act as a pull-through cache for a particular target registry instance. Harbor can only act a proxy for DockerHub, Docker Registry, Harbor, Aws ECR, Azure ACR, Quay and Google GCR registries.", "ENDPOINT": "Endpoint", - "PROXY_CACHE_ENDPOINT": "Proxy Cache Endpoint" + "PROXY_CACHE_ENDPOINT": "Proxy Cache Endpoint", + "NO_PROJECT": "We couldn't find any projects" }, "PROJECT_DETAIL": { "SUMMARY": "Özet", diff --git a/src/portal/src/i18n/lang/zh-cn-lang.json b/src/portal/src/i18n/lang/zh-cn-lang.json index 633a75e0a..ae4bc4f1b 100644 --- a/src/portal/src/i18n/lang/zh-cn-lang.json +++ b/src/portal/src/i18n/lang/zh-cn-lang.json @@ -253,7 +253,8 @@ "PROXY_CACHE": "镜像代理", "PROXY_CACHE_TOOLTIP": "开启此项,以使得该项目成为目标仓库的镜像代理.仅支持 DockerHub, Docker Registry, Harbor, Aws ECR, Azure ACR, Quay 和 Google GCR 类型的仓库", "ENDPOINT": "地址", - "PROXY_CACHE_ENDPOINT": "镜像代理地址" + "PROXY_CACHE_ENDPOINT": "镜像代理地址", + "NO_PROJECT": "未发现任何项目" }, "PROJECT_DETAIL": { "SUMMARY": "概要", diff --git a/src/portal/src/i18n/lang/zh-tw-lang.json b/src/portal/src/i18n/lang/zh-tw-lang.json index 90d1e2743..d6fc4ef49 100644 --- a/src/portal/src/i18n/lang/zh-tw-lang.json +++ b/src/portal/src/i18n/lang/zh-tw-lang.json @@ -251,7 +251,8 @@ "PROXY_CACHE": "Proxy Cache", "PROXY_CACHE_TOOLTIP": "Enable this to allow this project to act as a pull-through cache for a particular target registry instance. Harbor can only act a proxy for DockerHub, Docker Registry, Harbor, Aws ECR, Azure ACR, Quay and Google GCR registries.", "ENDPOINT": "Endpoint", - "PROXY_CACHE_ENDPOINT": "Proxy Cache Endpoint" + "PROXY_CACHE_ENDPOINT": "Proxy Cache Endpoint", + "NO_PROJECT": "We couldn't find any projects" }, "PROJECT_DETAIL":{ "SUMMARY": "概要",