From 04fa3853c923121d16f51e5729b2b473d3d0e8f4 Mon Sep 17 00:00:00 2001 From: Shijun Sun <30999793+AllForNothing@users.noreply.github.com> Date: Fri, 29 Jul 2022 19:04:01 +0800 Subject: [PATCH] Fix router issues for UI (#17235) Signed-off-by: AllForNothing --- .../history/purge-history.component.html | 12 +- .../history/purge-history.component.scss | 8 +- .../gc/gc-history/gc-history.component.html | 11 +- .../gc/gc-history/gc-history.component.scss | 8 +- .../left-side-nav/user/user.component.html | 6 +- .../artifact-list-page.component.spec.ts | 6 +- .../artifact-list-page.component.ts | 40 +- .../artifact-list-tab.component.html | 585 +++++++++--------- .../artifact-list-tab.component.scss | 6 +- .../artifact-list-tab.component.spec.ts | 31 +- .../artifact-list-tab.component.ts | 110 ++-- .../artifact/artifact-summary.component.html | 4 +- .../repository-gridview.component.scss | 1 + .../harbor-route-reuse-strategy.ts | 22 + src/portal/src/i18n/lang/de-de-lang.json | 4 +- src/portal/src/i18n/lang/en-us-lang.json | 4 +- src/portal/src/i18n/lang/es-es-lang.json | 4 +- src/portal/src/i18n/lang/fr-fr-lang.json | 4 +- src/portal/src/i18n/lang/pt-br-lang.json | 4 +- src/portal/src/i18n/lang/tr-tr-lang.json | 4 +- src/portal/src/i18n/lang/zh-cn-lang.json | 4 +- src/portal/src/i18n/lang/zh-tw-lang.json | 4 +- .../Project-Artifact-Elements.robot | 2 +- 23 files changed, 468 insertions(+), 416 deletions(-) diff --git a/src/portal/src/app/base/left-side-nav/clearing-job/audit-log-purge/history/purge-history.component.html b/src/portal/src/app/base/left-side-nav/clearing-job/audit-log-purge/history/purge-history.component.html index 6a3605335..e032de136 100644 --- a/src/portal/src/app/base/left-side-nav/clearing-job/audit-log-purge/history/purge-history.component.html +++ b/src/portal/src/app/base/left-side-nav/clearing-job/audit-log-purge/history/purge-history.component.html @@ -1,14 +1,12 @@
{{ 'CLEARANCES.PURGE_HISTORY' | translate }}
- - - + - +
+ + +
{{ 'GC.JOB_ID' | translate @@ -31,6 +32,9 @@ 'UPDATE_TIME' | translate }} {{ 'LOGS' | translate }} + {{ + 'CLEARANCES.NO_PURGE_RECORDS' | translate + }} {{ job.id }} {{ diff --git a/src/portal/src/app/base/left-side-nav/clearing-job/audit-log-purge/history/purge-history.component.scss b/src/portal/src/app/base/left-side-nav/clearing-job/audit-log-purge/history/purge-history.component.scss index 56f4d14e3..6f63db9c9 100644 --- a/src/portal/src/app/base/left-side-nav/clearing-job/audit-log-purge/history/purge-history.component.scss +++ b/src/portal/src/app/base/left-side-nav/clearing-job/audit-log-purge/history/purge-history.component.scss @@ -4,11 +4,17 @@ width: 97%; } +.action-bar { + display: flex; + align-items: center; + justify-content: space-between; +} + .refresh-btn { + margin-right: 2rem; cursor: pointer; &:hover { color: #007CBB; } } - \ No newline at end of file diff --git a/src/portal/src/app/base/left-side-nav/clearing-job/gc-page/gc/gc-history/gc-history.component.html b/src/portal/src/app/base/left-side-nav/clearing-job/gc-page/gc/gc-history/gc-history.component.html index 867770428..801e9f993 100644 --- a/src/portal/src/app/base/left-side-nav/clearing-job/gc-page/gc/gc-history/gc-history.component.html +++ b/src/portal/src/app/base/left-side-nav/clearing-job/gc-page/gc/gc-history/gc-history.component.html @@ -1,14 +1,11 @@
{{ 'GC.JOB_HISTORY' | translate }}
- - - - +
+ + +
{{ 'GC.JOB_ID' | translate @@ -31,6 +31,9 @@ 'UPDATE_TIME' | translate }} {{ 'LOGS' | translate }} + {{ + 'CLEARANCES.NO_GC_RECORDS' | translate + }} {{ job.id }} {{ diff --git a/src/portal/src/app/base/left-side-nav/clearing-job/gc-page/gc/gc-history/gc-history.component.scss b/src/portal/src/app/base/left-side-nav/clearing-job/gc-page/gc/gc-history/gc-history.component.scss index 56f4d14e3..6f63db9c9 100644 --- a/src/portal/src/app/base/left-side-nav/clearing-job/gc-page/gc/gc-history/gc-history.component.scss +++ b/src/portal/src/app/base/left-side-nav/clearing-job/gc-page/gc/gc-history/gc-history.component.scss @@ -4,11 +4,17 @@ width: 97%; } +.action-bar { + display: flex; + align-items: center; + justify-content: space-between; +} + .refresh-btn { + margin-right: 2rem; cursor: pointer; &:hover { color: #007CBB; } } - \ No newline at end of file diff --git a/src/portal/src/app/base/left-side-nav/user/user.component.html b/src/portal/src/app/base/left-side-nav/user/user.component.html index 2f4fbf615..51b5fba3f 100644 --- a/src/portal/src/app/base/left-side-nav/user/user.component.html +++ b/src/portal/src/app/base/left-side-nav/user/user.component.html @@ -59,8 +59,10 @@ type="button" class="btn btn-secondary" id="changePwd" - [hidden]="!canCreateUser" - [disabled]="!(selectedRow.length === 1)" + [disabled]=" + !(selectedRow.length === 1) || + !canCreateUser + " (click)="openChangePwdModal()">  {{ 'RESET_PWD.TITLE' | translate }} diff --git a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list-page.component.spec.ts b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list-page.component.spec.ts index 1a0a6a7cb..9c1d0b815 100644 --- a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list-page.component.spec.ts +++ b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list-page.component.spec.ts @@ -32,7 +32,11 @@ describe('ArtifactListPageComponent', () => { }), params: { subscribe: () => { - return of(null); + return { + unsubscribe() { + return null; + }, + }; }, }, }; diff --git a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list-page.component.ts b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list-page.component.ts index 56f81604c..17ba722dc 100644 --- a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list-page.component.ts +++ b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list-page.component.ts @@ -11,42 +11,53 @@ // 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 } from '@angular/core'; +import { Component, OnDestroy } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { Project } from '../../../project'; import { ArtifactListPageService } from './artifact-list-page.service'; +import { Subscription } from 'rxjs'; @Component({ selector: 'artifact-list-page', templateUrl: 'artifact-list-page.component.html', styleUrls: ['./artifact-list-page.component.scss'], }) -export class ArtifactListPageComponent implements OnInit { +export class ArtifactListPageComponent implements OnDestroy { projectId: string; projectName: string; repoName: string; referArtifactNameArray: string[] = []; depth: string; artifactDigest: string; + routeParamsSub: Subscription; constructor( private route: ActivatedRoute, private router: Router, private artifactListPageService: ArtifactListPageService ) { - this.route.params.subscribe(params => { - this.depth = this.route.snapshot.params['depth']; - if (this.depth) { - const arr: string[] = this.depth.split('-'); - this.referArtifactNameArray = arr.slice(0, arr.length - 1); - this.artifactDigest = this.depth.split('-')[arr.length - 1]; - } else { - this.referArtifactNameArray = []; - this.artifactDigest = null; - } - }); + if (!this.routeParamsSub) { + this.routeParamsSub = this.route.params.subscribe(params => { + this.depth = this.route.snapshot.firstChild.params['depth']; + if (this.depth) { + const arr: string[] = this.depth.split('-'); + this.referArtifactNameArray = arr.slice(0, arr.length - 1); + this.artifactDigest = this.depth.split('-')[arr.length - 1]; + } else { + this.referArtifactNameArray = []; + this.artifactDigest = null; + } + this.init(); + }); + } + } + ngOnDestroy() { + if (this.routeParamsSub) { + this.routeParamsSub.unsubscribe(); + this.routeParamsSub = null; + } } - ngOnInit() { + init() { this.projectId = this.route.snapshot.parent.params['id']; let resolverData = this.route.snapshot.parent.data; if (resolverData) { @@ -55,7 +66,6 @@ export class ArtifactListPageComponent implements OnInit { this.repoName = this.route.snapshot.params['repo']; this.artifactListPageService.init(+this.projectId); } - watchGoBackEvt(projectId: string | number): void { this.router.navigate(['harbor', 'projects', projectId, 'repositories']); } diff --git a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.html b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.html index f66413ac4..04f52c614 100644 --- a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.html +++ b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.html @@ -55,298 +55,321 @@
-
-
-
-
- -
-
-
-
- - - -
-
- - -
-
-
    -
  • - {{ item.showItem | translate }} -
  • -
-
-
-
- × - -
- -
-
- {{ 'LABEL.NO_LABELS' | translate }} -
-
- -
-
-
-
-
-
- - - -
-
- - - - - - - - {{ 'BUTTON.ACTIONS' | translate }} - - - -
- {{ 'REPOSITORY.COPY_DIGEST_ID' | translate }} -
- - + + + + {{ 'BUTTON.ACTIONS' | translate }} + + + +
- {{ 'REPOSITORY.ADD_LABELS' | translate }} - - -
- -
- -
-
- {{ 'LABEL.NO_LABELS' | translate }} -
-
-
+ + + +
+ +
+ +
+
- - -
- - -
- + class="no-labels"> + {{ 'LABEL.NO_LABELS' | translate }} +
+
+ +
+
+
+
+
+ {{ 'REPOSITORY.RETAG' | translate }} +
+
+ {{ 'REPOSITORY.DELETE' | translate }} +
+ + +
+
+
+
+ +
+
+
+
+ + + +
+
+ + +
+
+
    +
  • + {{ + item.showItem + | translate + }} +
  • +
+
+
+
+ × + +
+ +
+
+ {{ 'LABEL.NO_LABELS' | translate }} +
+
+ +
- - -
- {{ 'REPOSITORY.RETAG' | translate }} +
-
- {{ 'REPOSITORY.DELETE' | translate }} -
- - +
+ + + +
{ let spyLabels: jasmine.Spy; let spyLabels1: jasmine.Spy; let spyScanner: jasmine.Spy; - let scannerMock = { + const scannerMock = { disabled: false, name: 'Trivy', }; - let mockActivatedRoute = { + const mockActivatedRoute = { snapshot: { params: { id: 1, repo: 'test', digest: 'ABC', - subscribe: () => { - return of(null); - }, }, data: { projectResolver: { @@ -70,13 +63,8 @@ describe('ArtifactListTabComponent (inline template)', () => { name: 'library', }, }), - params: { - subscribe: () => { - return of(null); - }, - }, }; - let mockArtifacts: Artifact[] = [ + const mockArtifacts: Artifact[] = [ { id: 1, type: 'image', @@ -266,6 +254,11 @@ describe('ArtifactListTabComponent (inline template)', () => { }, ]; const mockRouter = { + events: { + subscribe: () => { + return of(null); + }, + }, navigate: () => {}, }; const mockOperationService = { @@ -351,13 +344,7 @@ describe('ArtifactListTabComponent (inline template)', () => { await TestBed.configureTestingModule({ imports: [SharedTestingModule], schemas: [CUSTOM_ELEMENTS_SCHEMA], - declarations: [ - ArtifactListTabComponent, - LabelPieceComponent, - ConfirmationDialogComponent, - ImageNameInputComponent, - CopyInputComponent, - ], + declarations: [ArtifactListTabComponent], providers: [ { provide: ArtifactListPageService, diff --git a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.ts b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.ts index 50da5e9c0..127867629 100644 --- a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.ts +++ b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.ts @@ -197,11 +197,8 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy { onSendingStopScanCommand: boolean = false; onStopScanArtifactsLength: number = 0; scanStoppedArtifactLength: number = 0; - artifactDigest: string; depth: string; - hasInit: boolean = false; - triggerSub: Subscription; labelNameFilterSub: Subscription; stickLabelNameFilterSub: Subscription; mutipleFilter = clone(mutipleFilter); @@ -209,7 +206,6 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy { openSelectFilterPiece = false; // could Pagination filter filters: string[]; - scanFinishedArtifactLength: number = 0; onScanArtifactsLength: number = 0; stopBtnState: ClrLoadingState = ClrLoadingState.DEFAULT; @@ -226,38 +222,33 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy { private appConfigService: AppConfigService, public artifactListPageService: ArtifactListPageService ) {} - - ngOnInit() { - this.artifactListPageService.resetClonedLabels(); + initRouterData() { this.projectId = this.activatedRoute.snapshot?.parent?.parent?.params['id']; - let resolverData = this.activatedRoute.snapshot?.parent?.parent?.data; + if (!this.projectId) { + this.errorHandlerService.error('Project ID cannot be unset.'); + return; + } + const resolverData = this.activatedRoute.snapshot?.parent?.parent?.data; if (resolverData) { this.projectName = (resolverData['projectResolver']).name; } this.repoName = this.activatedRoute.snapshot?.parent?.params['repo']; + if (!this.repoName) { + this.errorHandlerService.error('Repo name cannot be unset.'); + return; + } + this.depth = this.activatedRoute.snapshot.params['depth']; + if (this.depth) { + const arr: string[] = this.depth.split('-'); + this.artifactDigest = this.depth.split('-')[arr.length - 1]; + } + this.lastFilteredTagName = ''; + } + ngOnInit() { + this.artifactListPageService.resetClonedLabels(); this.registryUrl = this.appConfigService.getConfig().registry_url; - this.activatedRoute.params?.subscribe(params => { - this.depth = - this.activatedRoute.snapshot?.firstChild?.params['depth']; - if (this.depth) { - const arr: string[] = this.depth.split('-'); - this.artifactDigest = this.depth.split('-')[arr.length - 1]; - } - if (this.hasInit) { - this.currentPage = 1; - this.totalCount = 0; - const st: ClrDatagridStateInterface = { - page: { - from: 0, - to: this.pageSize - 1, - size: this.pageSize, - }, - }; - this.clrLoad(st); - } - this.init(); - }); + this.initRouterData(); if (!this.updateArtifactSub) { this.updateArtifactSub = this.eventService.subscribe( HarborEvent.UPDATE_VULNERABILITY_INFO, @@ -272,48 +263,6 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy { } ); } - } - - ngOnDestroy() { - if (this.triggerSub) { - this.triggerSub.unsubscribe(); - this.triggerSub = null; - } - if (this.labelNameFilterSub) { - this.labelNameFilterSub.unsubscribe(); - this.labelNameFilterSub = null; - } - if (this.stickLabelNameFilterSub) { - this.stickLabelNameFilterSub.unsubscribe(); - this.stickLabelNameFilterSub = null; - } - if (this.updateArtifactSub) { - this.updateArtifactSub.unsubscribe(); - this.updateArtifactSub = null; - } - } - - init() { - this.hasInit = true; - this.depth = this.activatedRoute.snapshot.params['depth']; - if (this.depth) { - const arr: string[] = this.depth.split('-'); - this.artifactDigest = this.depth.split('-')[arr.length - 1]; - } - if (!this.projectId) { - this.errorHandlerService.error('Project ID cannot be unset.'); - return; - } - const resolverData = this.activatedRoute.snapshot.params.data; - if (resolverData) { - const pro: Project = resolverData['projectResolver']; - this.projectName = pro.name; - } - if (!this.repoName) { - this.errorHandlerService.error('Repo name cannot be unset.'); - return; - } - this.lastFilteredTagName = ''; if (!this.labelNameFilterSub) { this.labelNameFilterSub = this.labelNameFilter .pipe(debounceTime(500)) @@ -349,7 +298,20 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy { }); } } - + ngOnDestroy() { + if (this.labelNameFilterSub) { + this.labelNameFilterSub.unsubscribe(); + this.labelNameFilterSub = null; + } + if (this.stickLabelNameFilterSub) { + this.stickLabelNameFilterSub.unsubscribe(); + this.stickLabelNameFilterSub = null; + } + if (this.updateArtifactSub) { + this.updateArtifactSub.unsubscribe(); + this.updateArtifactSub = null; + } + } public get filterLabelPieceWidth() { let len = this.lastFilteredTagName.length ? this.lastFilteredTagName.length * 6 + 60 @@ -381,11 +343,11 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy { this.clrLoad(st); } - // todo clrDgRefresh(state: ClrDatagridStateInterface) { setTimeout(() => { + //add setTimeout to avoid ng check error this.clrLoad(state); - }); + }, 0); } clrLoad(state: ClrDatagridStateInterface): void { diff --git a/src/portal/src/app/base/project/repository/artifact/artifact-summary.component.html b/src/portal/src/app/base/project/repository/artifact/artifact-summary.component.html index 93b362354..aee409948 100644 --- a/src/portal/src/app/base/project/repository/artifact/artifact-summary.component.html +++ b/src/portal/src/app/base/project/repository/artifact/artifact-summary.component.html @@ -8,7 +8,9 @@ < {{ repositoryName }} - + <{{ digest | slice: 0:15 }}
diff --git a/src/portal/src/app/base/project/repository/repository-gridview.component.scss b/src/portal/src/app/base/project/repository/repository-gridview.component.scss index a1074dc6f..47b3c820d 100644 --- a/src/portal/src/app/base/project/repository/repository-gridview.component.scss +++ b/src/portal/src/app/base/project/repository/repository-gridview.component.scss @@ -51,6 +51,7 @@ } .download-link { + margin-bottom: 8px; font-size: 14px; } diff --git a/src/portal/src/app/route-reuse-strategy/harbor-route-reuse-strategy.ts b/src/portal/src/app/route-reuse-strategy/harbor-route-reuse-strategy.ts index 69b940122..441112ace 100644 --- a/src/portal/src/app/route-reuse-strategy/harbor-route-reuse-strategy.ts +++ b/src/portal/src/app/route-reuse-strategy/harbor-route-reuse-strategy.ts @@ -18,6 +18,22 @@ export enum RouteConfigId { P2P_POLICIES_PAGE = 'PolicyComponent', P2P_TASKS_PAGE = 'P2pTaskListComponent', } +// should not reuse the routes that meet these RegExps +const ShouldNotReuseRouteRegExps: RegExp[] = [ + /\/harbor\/projects\/(\d+)\/repositories$/, + /\/harbor\/projects\/(\d+)\/repositories\/(\S+)\/artifacts-tab$/, + /\/harbor\/projects\/(\d+)\/helm-charts\/(\S+)\/versions\/(\S+)/, +]; + +function testRoute(url: string) { + let flag: boolean = false; + ShouldNotReuseRouteRegExps.forEach(item => { + if (item.test(url)) { + flag = true; + } + }); + return flag; +} export class HarborRouteReuseStrategy implements RouteReuseStrategy { /** @@ -73,6 +89,12 @@ export class HarborRouteReuseStrategy implements RouteReuseStrategy { curr: ActivatedRouteSnapshot ): boolean { this.shouldKeepCache(future, curr); + if ( + testRoute(curr['_routerState']?.url) && + testRoute(future['_routerState']?.url) + ) { + return false; + } return future.routeConfig === curr.routeConfig; } diff --git a/src/portal/src/i18n/lang/de-de-lang.json b/src/portal/src/i18n/lang/de-de-lang.json index ba0958b19..24197b4f7 100644 --- a/src/portal/src/i18n/lang/de-de-lang.json +++ b/src/portal/src/i18n/lang/de-de-lang.json @@ -1752,7 +1752,9 @@ "SKIP_DATABASE": "Skip Audit Log Database", "SKIP_DATABASE_TOOLTIP": "Skip to log audit log in the database, only available when audit log forward endpoint is configured", "STOP_GC_SUCCESS": "Trigger stopping GC operation successfully", - "STOP_PURGE_SUCCESS": "Trigger stopping purging operation successfully" + "STOP_PURGE_SUCCESS": "Trigger stopping purging operation successfully", + "NO_GC_RECORDS": "We couldn't find any GC histories!", + "NO_PURGE_RECORDS": "We couldn't find any purge histories!" }, "CVE_EXPORT": { "EXPORT_SOME_PROJECTS": "Export CVEs - {{number}} project(s)", diff --git a/src/portal/src/i18n/lang/en-us-lang.json b/src/portal/src/i18n/lang/en-us-lang.json index 3121af42c..43537ba2f 100644 --- a/src/portal/src/i18n/lang/en-us-lang.json +++ b/src/portal/src/i18n/lang/en-us-lang.json @@ -1752,7 +1752,9 @@ "SKIP_DATABASE": "Skip Audit Log Database", "SKIP_DATABASE_TOOLTIP": "Skip to log audit log in the database, only available when audit log forward endpoint is configured", "STOP_GC_SUCCESS": "Trigger stopping GC operation successfully", - "STOP_PURGE_SUCCESS": "Trigger stopping purging operation successfully" + "STOP_PURGE_SUCCESS": "Trigger stopping purging operation successfully", + "NO_GC_RECORDS": "We couldn't find any GC histories!", + "NO_PURGE_RECORDS": "We couldn't find any purge histories!" }, "CVE_EXPORT": { "EXPORT_SOME_PROJECTS": "Export CVEs - {{number}} project(s)", diff --git a/src/portal/src/i18n/lang/es-es-lang.json b/src/portal/src/i18n/lang/es-es-lang.json index 3dd1de210..b984a0da8 100644 --- a/src/portal/src/i18n/lang/es-es-lang.json +++ b/src/portal/src/i18n/lang/es-es-lang.json @@ -1751,7 +1751,9 @@ "SKIP_DATABASE": "Skip Audit Log Database", "SKIP_DATABASE_TOOLTIP": "Skip to log audit log in the database, only available when audit log forward endpoint is configured", "STOP_GC_SUCCESS": "Trigger stopping GC operation successfully", - "STOP_PURGE_SUCCESS": "Trigger stopping purging operation successfully" + "STOP_PURGE_SUCCESS": "Trigger stopping purging operation successfully", + "NO_GC_RECORDS": "We couldn't find any GC histories!", + "NO_PURGE_RECORDS": "We couldn't find any purge histories!" }, "CVE_EXPORT": { "EXPORT_SOME_PROJECTS": "Export CVEs - {{number}} project(s)", diff --git a/src/portal/src/i18n/lang/fr-fr-lang.json b/src/portal/src/i18n/lang/fr-fr-lang.json index 21cac8650..66655bb33 100644 --- a/src/portal/src/i18n/lang/fr-fr-lang.json +++ b/src/portal/src/i18n/lang/fr-fr-lang.json @@ -1721,7 +1721,9 @@ "SKIP_DATABASE": "Skip Audit Log Database", "SKIP_DATABASE_TOOLTIP": "Skip to log audit log in the database, only available when audit log forward endpoint is configured", "STOP_GC_SUCCESS": "Trigger stopping GC operation successfully", - "STOP_PURGE_SUCCESS": "Trigger stopping purging operation successfully" + "STOP_PURGE_SUCCESS": "Trigger stopping purging operation successfully", + "NO_GC_RECORDS": "We couldn't find any GC histories!", + "NO_PURGE_RECORDS": "We couldn't find any purge histories!" }, "CVE_EXPORT": { "EXPORT_SOME_PROJECTS": "Export CVEs - {{number}} project(s)", diff --git a/src/portal/src/i18n/lang/pt-br-lang.json b/src/portal/src/i18n/lang/pt-br-lang.json index 93c2ae30d..a61486000 100644 --- a/src/portal/src/i18n/lang/pt-br-lang.json +++ b/src/portal/src/i18n/lang/pt-br-lang.json @@ -1748,7 +1748,9 @@ "SKIP_DATABASE": "Skip Audit Log Database", "SKIP_DATABASE_TOOLTIP": "Skip to log audit log in the database, only available when audit log forward endpoint is configured", "STOP_GC_SUCCESS": "Trigger stopping GC operation successfully", - "STOP_PURGE_SUCCESS": "Trigger stopping purging operation successfully" + "STOP_PURGE_SUCCESS": "Trigger stopping purging operation successfully", + "NO_GC_RECORDS": "We couldn't find any GC histories!", + "NO_PURGE_RECORDS": "We couldn't find any purge histories!" }, "CVE_EXPORT": { "EXPORT_SOME_PROJECTS": "Export CVEs - {{number}} project(s)", diff --git a/src/portal/src/i18n/lang/tr-tr-lang.json b/src/portal/src/i18n/lang/tr-tr-lang.json index 8e05f1413..e65c18cd5 100644 --- a/src/portal/src/i18n/lang/tr-tr-lang.json +++ b/src/portal/src/i18n/lang/tr-tr-lang.json @@ -1752,7 +1752,9 @@ "SKIP_DATABASE": "Skip Audit Log Database", "SKIP_DATABASE_TOOLTIP": "Skip to log audit log in the database, only available when audit log forward endpoint is configured", "STOP_GC_SUCCESS": "Trigger stopping GC operation successfully", - "STOP_PURGE_SUCCESS": "Trigger stopping purging operation successfully" + "STOP_PURGE_SUCCESS": "Trigger stopping purging operation successfully", + "NO_GC_RECORDS": "We couldn't find any GC histories!", + "NO_PURGE_RECORDS": "We couldn't find any purge histories!" }, "CVE_EXPORT": { "EXPORT_SOME_PROJECTS": "Export CVEs - {{number}} project(s)", diff --git a/src/portal/src/i18n/lang/zh-cn-lang.json b/src/portal/src/i18n/lang/zh-cn-lang.json index 0e5eb1c36..7f04c434a 100644 --- a/src/portal/src/i18n/lang/zh-cn-lang.json +++ b/src/portal/src/i18n/lang/zh-cn-lang.json @@ -1750,7 +1750,9 @@ "SKIP_DATABASE": "跳过日志数据库", "SKIP_DATABASE_TOOLTIP": "开启此项将不会在数据库中记录日志,需先配置日志转发端点", "STOP_GC_SUCCESS": "成功触发停止垃圾回收的操作", - "STOP_PURGE_SUCCESS": "成功触发停止清理日志的操作" + "STOP_PURGE_SUCCESS": "成功触发停止清理日志的操作", + "NO_GC_RECORDS": "未发现任何清理记录!", + "NO_PURGE_RECORDS": "未发现任何清理记录!" }, "CVE_EXPORT": { "EXPORT_SOME_PROJECTS": "导出 CVEs - {{number}} 个项目", diff --git a/src/portal/src/i18n/lang/zh-tw-lang.json b/src/portal/src/i18n/lang/zh-tw-lang.json index 05aff1ffc..9eeee7dcf 100644 --- a/src/portal/src/i18n/lang/zh-tw-lang.json +++ b/src/portal/src/i18n/lang/zh-tw-lang.json @@ -1743,7 +1743,9 @@ "SKIP_DATABASE": "Skip Audit Log Database", "SKIP_DATABASE_TOOLTIP": "Skip to log audit log in the database, only available when audit log forward endpoint is configured", "STOP_GC_SUCCESS": "Trigger stopping GC operation successfully", - "STOP_PURGE_SUCCESS": "Trigger stopping purging operation successfully" + "STOP_PURGE_SUCCESS": "Trigger stopping purging operation successfully", + "NO_GC_RECORDS": "We couldn't find any GC histories!", + "NO_PURGE_RECORDS": "We couldn't find any purge histories!" }, "CVE_EXPORT": { "EXPORT_SOME_PROJECTS": "Export CVEs - {{number}} project(s)", diff --git a/tests/resources/Harbor-Pages/Project-Artifact-Elements.robot b/tests/resources/Harbor-Pages/Project-Artifact-Elements.robot index e565def71..ec18f2a83 100644 --- a/tests/resources/Harbor-Pages/Project-Artifact-Elements.robot +++ b/tests/resources/Harbor-Pages/Project-Artifact-Elements.robot @@ -16,7 +16,7 @@ Documentation This resource provides any keywords related to the Harbor private registry appliance *** Variables *** -${artifact_action_xpath} //clr-dg-action-bar/clr-dropdown/span[contains(@class,'dropdown-toggle')] +${artifact_action_xpath} //*[@id='artifact-list-action'] ${artifact_action_delete_xpath} //clr-dropdown-menu//div[contains(.,'Delete')] ${artifact_action_copy_xpath} //clr-dropdown-menu//div[contains(.,'Copy') and @aria-label='retag'] ${artifact_achieve_icon} //artifact-list-tab//clr-datagrid//clr-dg-row[contains(.,'sha256')]//clr-dg-cell[1]//clr-tooltip//a