diff --git a/src/portal/src/app/base/left-side-nav/system-robot-accounts/system-robot-accounts.component.html b/src/portal/src/app/base/left-side-nav/system-robot-accounts/system-robot-accounts.component.html
index 6864313a5..5bb0093c2 100644
--- a/src/portal/src/app/base/left-side-nav/system-robot-accounts/system-robot-accounts.component.html
+++ b/src/portal/src/app/base/left-side-nav/system-robot-accounts/system-robot-accounts.component.html
@@ -60,7 +60,7 @@
{{'ROBOT_ACCOUNT.ENABLED_STATE' | translate}}
{{"SYSTEM_ROBOT.PROJECTS" | translate}}
{{'ROBOT_ACCOUNT.CREATETION' | translate}}
- {{'SYSTEM_ROBOT.EXPIRES_AT' | translate}}
+ {{'SYSTEM_ROBOT.EXPIRES_IN' | translate}}
{{'ROBOT_ACCOUNT.DESCRIPTION' | translate}}
{{
'SYSTEM_ROBOT.NOT_FOUND' | translate
@@ -96,7 +96,7 @@
{{r.creation_time | harborDatetime: 'short'}}
- {{r.expires_at === -1?("ROBOT_ACCOUNT.NEVER_EXPIRED" | translate):(r.expires_at * 1000 | harborDatetime: 'short')}}
+
{{r.description}}
diff --git a/src/portal/src/app/base/left-side-nav/system-robot-accounts/system-robot-accounts.component.spec.ts b/src/portal/src/app/base/left-side-nav/system-robot-accounts/system-robot-accounts.component.spec.ts
index f74755356..ef3722561 100644
--- a/src/portal/src/app/base/left-side-nav/system-robot-accounts/system-robot-accounts.component.spec.ts
+++ b/src/portal/src/app/base/left-side-nav/system-robot-accounts/system-robot-accounts.component.spec.ts
@@ -12,7 +12,13 @@ import { ProjectService } from "../../../../../ng-swagger-gen/services/project.s
import { MessageHandlerService } from "../../../shared/services/message-handler.service";
import { OperationService } from "../../../shared/components/operation/operation.service";
import { ConfirmationDialogService } from "../../global-confirmation-dialog/confirmation-dialog.service";
-import { SharedTestingModule } from "../../../shared/shared.module";
+import { TranslateModule, TranslateService } from '@ngx-translate/core';
+import { CommonModule } from '@angular/common';
+import { ClarityModule } from '@clr/angular';
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { RouterTestingModule } from '@angular/router/testing';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { HarborDatetimePipe } from '../../../shared/pipes/harbor-datetime.pipe';
describe('SystemRobotAccountsComponent', () => {
let component: SystemRobotAccountsComponent;
@@ -119,10 +125,16 @@ describe('SystemRobotAccountsComponent', () => {
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
imports: [
- SharedTestingModule
+ TranslateModule.forRoot(),
+ CommonModule,
+ ClarityModule,
+ HttpClientTestingModule,
+ RouterTestingModule,
+ BrowserAnimationsModule,
],
- declarations: [ SystemRobotAccountsComponent ],
+ declarations: [ SystemRobotAccountsComponent, HarborDatetimePipe],
providers: [
+ TranslateService,
{ provide: MessageHandlerService, useValue: fakedMessageHandlerService },
ConfirmationDialogService,
OperationService,
diff --git a/src/portal/src/app/base/left-side-nav/system-robot-accounts/system-robot-accounts.component.ts b/src/portal/src/app/base/left-side-nav/system-robot-accounts/system-robot-accounts.component.ts
index 88a539a3c..743882b14 100644
--- a/src/portal/src/app/base/left-side-nav/system-robot-accounts/system-robot-accounts.component.ts
+++ b/src/portal/src/app/base/left-side-nav/system-robot-accounts/system-robot-accounts.component.ts
@@ -28,6 +28,7 @@ import { ConfirmationButtons, ConfirmationState, ConfirmationTargets } from "../
import { errorHandler } from "../../../shared/units/shared.utils";
import { ConfirmationMessage } from "../../global-confirmation-dialog/confirmation-message";
import { RobotPermission } from "../../../../../ng-swagger-gen/models/robot-permission";
+import { SysteminfoService } from '../../../../../ng-swagger-gen/services/systeminfo.service';
const FIRST_PROJECTS_PAGE_SIZE: number = 100;
@Component({
@@ -56,6 +57,7 @@ export class SystemRobotAccountsComponent implements OnInit, OnDestroy {
searchSub: Subscription;
searchKey: string;
subscription: Subscription;
+ deltaTime: number; // the different between server time and local time
constructor(private robotService: RobotService,
private projectService: ProjectService,
private msgHandler: MessageHandlerService,
@@ -63,8 +65,10 @@ export class SystemRobotAccountsComponent implements OnInit, OnDestroy {
private operationService: OperationService,
private sanitizer: DomSanitizer,
private translate: TranslateService,
+ private systemInfoService: SysteminfoService
) {}
ngOnInit() {
+ this.getCurrenTime();
this.loadDataFromBackend();
if (!this.searchSub) {
this.searchSub = this.filterComponent.filterTerms.pipe(
@@ -124,6 +128,15 @@ export class SystemRobotAccountsComponent implements OnInit, OnDestroy {
this.subscription = null;
}
}
+ getCurrenTime() {
+ this.systemInfoService.getSystemInfo().subscribe(
+ res => {
+ if (res?.current_time) {
+ this.deltaTime = new Date().getTime() - new Date(res?.current_time).getTime();
+ }
+ }
+ );
+ }
loadDataFromBackend() {
this.loadingData = true;
this.addBtnState = ClrLoadingState.LOADING;
diff --git a/src/portal/src/app/base/left-side-nav/system-robot-accounts/system-robot-util.ts b/src/portal/src/app/base/left-side-nav/system-robot-accounts/system-robot-util.ts
index 1b17b88f9..1597fa5f8 100644
--- a/src/portal/src/app/base/left-side-nav/system-robot-accounts/system-robot-util.ts
+++ b/src/portal/src/app/base/left-side-nav/system-robot-accounts/system-robot-util.ts
@@ -172,3 +172,9 @@ export function onlyHasPushPermission(access: Access[]): boolean {
}
return false;
}
+
+export enum RobotTimeRemainColor {
+ GREEN = 'green',
+ WARNING = 'yellow',
+ EXPIRED = 'red'
+}
diff --git a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.spec.ts b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.spec.ts
index 7cfc5ad36..7946c87e9 100644
--- a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.spec.ts
+++ b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.spec.ts
@@ -31,6 +31,7 @@ import { Registry } from "../../../../../../../../../ng-swagger-gen/models/regis
import { AppConfigService } from "../../../../../../../services/app-config.service";
import { ArtifactListPageService } from '../../artifact-list-page.service';
import { ClrLoadingState } from '@clr/angular';
+import { Accessory } from "ng-swagger-gen/models/accessory";
describe("ArtifactListTabComponent (inline template)", () => {
@@ -263,6 +264,16 @@ describe("ArtifactListTabComponent (inline template)", () => {
}
},
+ listAccessoriesResponse() {
+ const res: HttpResponse> = new HttpResponse>({
+ headers: new HttpHeaders({'x-total-count': '0'}),
+ body: []
+ });
+ return of(res).pipe(delay(0));
+ },
+ listAccessories() {
+ return of(null).pipe(delay(0));
+ },
listArtifactsResponse: () => {
if (filtereName === 'sha256:3e33e3e3') {
return of(
diff --git a/src/portal/src/app/base/project/robot-account/robot-account.component.html b/src/portal/src/app/base/project/robot-account/robot-account.component.html
index a2aef2618..1975c7f29 100644
--- a/src/portal/src/app/base/project/robot-account/robot-account.component.html
+++ b/src/portal/src/app/base/project/robot-account/robot-account.component.html
@@ -59,7 +59,7 @@
{{'ROBOT_ACCOUNT.ENABLED_STATE' | translate}}
{{"SYSTEM_ROBOT.PERMISSION_COLUMN" | translate}}
{{'ROBOT_ACCOUNT.CREATETION' | translate}}
- {{'SYSTEM_ROBOT.EXPIRES_AT' | translate}}
+ {{'SYSTEM_ROBOT.EXPIRES_IN' | translate}}
{{'ROBOT_ACCOUNT.DESCRIPTION' | translate}}
{{
'SYSTEM_ROBOT.NOT_FOUND' | translate
@@ -89,7 +89,7 @@
{{r.creation_time | harborDatetime: 'short'}}
- {{r.expires_at === -1?("ROBOT_ACCOUNT.NEVER_EXPIRED" | translate):(r.expires_at * 1000 | harborDatetime: 'short')}}
+
{{r.description}}
diff --git a/src/portal/src/app/base/project/robot-account/robot-account.component.spec.ts b/src/portal/src/app/base/project/robot-account/robot-account.component.spec.ts
index a01f6a243..5d10390c3 100644
--- a/src/portal/src/app/base/project/robot-account/robot-account.component.spec.ts
+++ b/src/portal/src/app/base/project/robot-account/robot-account.component.spec.ts
@@ -1,7 +1,7 @@
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { of, Subscription } from 'rxjs';
-import { ActivatedRoute } from "@angular/router";
+import { ActivatedRoute, RouterModule } from "@angular/router";
import { MessageHandlerService } from "../../../shared/services/message-handler.service";
import { RobotAccountComponent } from './robot-account.component';
import { UserPermissionService } from "../../../shared/services";
@@ -12,7 +12,13 @@ import { Robot } from "../../../../../ng-swagger-gen/models/robot";
import { delay } from "rxjs/operators";
import { Action, PermissionsKinds, Resource } from "../../left-side-nav/system-robot-accounts/system-robot-util";
import { ConfirmationDialogService } from "../../global-confirmation-dialog/confirmation-dialog.service";
-import { SharedTestingModule } from "../../../shared/shared.module";
+import { TranslateModule, TranslateService } from '@ngx-translate/core';
+import { CommonModule } from '@angular/common';
+import { ClarityModule } from '@clr/angular';
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { RouterTestingModule } from '@angular/router/testing';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { HarborDatetimePipe } from '../../../shared/pipes/harbor-datetime.pipe';
describe('RobotAccountComponent', () => {
let component: RobotAccountComponent;
@@ -106,9 +112,15 @@ describe('RobotAccountComponent', () => {
NO_ERRORS_SCHEMA
],
imports: [
- SharedTestingModule,
+ TranslateModule.forRoot(),
+ CommonModule,
+ ClarityModule,
+ HttpClientTestingModule,
+ RouterTestingModule,
+ BrowserAnimationsModule,
],
providers: [
+ TranslateService,
{
provide: ActivatedRoute, useValue: {
snapshot: {
@@ -127,7 +139,7 @@ describe('RobotAccountComponent', () => {
{ provide: UserPermissionService, useValue: mockUserPermissionService },
{ provide: RobotService, useValue: fakedRobotService},
],
- declarations: [RobotAccountComponent]
+ declarations: [RobotAccountComponent, HarborDatetimePipe]
}).compileComponents();
}));
diff --git a/src/portal/src/app/base/project/robot-account/robot-account.component.ts b/src/portal/src/app/base/project/robot-account/robot-account.component.ts
index 13365e47d..1cebf9065 100644
--- a/src/portal/src/app/base/project/robot-account/robot-account.component.ts
+++ b/src/portal/src/app/base/project/robot-account/robot-account.component.ts
@@ -25,6 +25,7 @@ import { ConfirmationDialogService } from "../../global-confirmation-dialog/conf
import { ConfirmationButtons, ConfirmationState, ConfirmationTargets } from "../../../shared/entities/shared.const";
import { errorHandler } from "../../../shared/units/shared.utils";
import { ConfirmationMessage } from "../../global-confirmation-dialog/confirmation-message";
+import { SysteminfoService } from '../../../../../ng-swagger-gen/services/systeminfo.service';
@Component({
selector: "app-robot-account",
@@ -55,6 +56,7 @@ export class RobotAccountComponent implements OnInit, OnDestroy {
hasRobotReadPermission: boolean;
projectId: number;
projectName: string;
+ deltaTime: number; // the different between server time and local time
constructor(private robotService: RobotService,
private msgHandler: MessageHandlerService,
private operateDialogService: ConfirmationDialogService,
@@ -63,8 +65,10 @@ export class RobotAccountComponent implements OnInit, OnDestroy {
private route: ActivatedRoute,
private translate: TranslateService,
private sanitizer: DomSanitizer,
+ private systemInfoService: SysteminfoService
) {}
ngOnInit() {
+ this.getCurrenTime();
this.projectId = +this.route.snapshot.parent.parent.params["id"];
let resolverData = this.route.snapshot.parent.parent.data;
if (resolverData) {
@@ -121,6 +125,15 @@ export class RobotAccountComponent implements OnInit, OnDestroy {
);
}
}
+ getCurrenTime() {
+ this.systemInfoService.getSystemInfo().subscribe(
+ res => {
+ if (res?.current_time) {
+ this.deltaTime = new Date().getTime() - new Date(res?.current_time).getTime();
+ }
+ }
+ );
+ }
getPermissionsList(): void {
let permissionsList = [];
permissionsList.push(this.userPermissionService.getPermission(this.projectId,
diff --git a/src/portal/src/app/shared/components/remaining-time/remaining-time.component.html b/src/portal/src/app/shared/components/remaining-time/remaining-time.component.html
new file mode 100644
index 000000000..69bb6af90
--- /dev/null
+++ b/src/portal/src/app/shared/components/remaining-time/remaining-time.component.html
@@ -0,0 +1 @@
+{{timeRemain | translate}}
diff --git a/src/portal/src/app/shared/components/remaining-time/remaining-time.component.scss b/src/portal/src/app/shared/components/remaining-time/remaining-time.component.scss
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/portal/src/app/shared/components/remaining-time/remaining-time.component.spec.ts b/src/portal/src/app/shared/components/remaining-time/remaining-time.component.spec.ts
new file mode 100644
index 000000000..a90b7ba88
--- /dev/null
+++ b/src/portal/src/app/shared/components/remaining-time/remaining-time.component.spec.ts
@@ -0,0 +1,62 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { RemainingTimeComponent } from './remaining-time.component';
+import { Component, ViewChild } from '@angular/core';
+import { Project } from '../../../../../ng-swagger-gen/models/project';
+import { RobotTimeRemainColor } from '../../../base/left-side-nav/system-robot-accounts/system-robot-util';
+import { SharedTestingModule } from '../../shared.module';
+
+
+describe('RemainingTimeComponent', () => {
+ let component: TestHostComponent;
+ let fixture: ComponentFixture;
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ imports: [
+ SharedTestingModule
+ ],
+ declarations: [TestHostComponent, RemainingTimeComponent],
+ }).compileComponents();
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(TestHostComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+ it('should show green color', () => {
+ fixture.detectChanges();
+ expect(component?.remainingTimeComponent.color).toEqual(RobotTimeRemainColor.GREEN);
+ expect(component?.remainingTimeComponent.timeRemain).toEqual('ROBOT_ACCOUNT.NEVER_EXPIRED');
+ });
+ it('should show yellow color', () => {
+ component.deltaTime = 0;
+ component.expires_at = new Date(new Date().getTime() + 1000 * 60 * 60 * 24 * 29).getTime() / 1000;
+ fixture.detectChanges();
+ expect(component?.remainingTimeComponent.color).toEqual(RobotTimeRemainColor.WARNING);
+ expect(component?.remainingTimeComponent.timeRemain).toEqual('29d 0h 0m');
+ });
+ it('should show red color', () => {
+ component.deltaTime = 0;
+ component.expires_at = new Date(new Date().getTime() - 1000 * 60 * 60 * 24 * 31).getTime() / 1000;
+ fixture.detectChanges();
+ expect(component?.remainingTimeComponent.color).toEqual(RobotTimeRemainColor.EXPIRED);
+ expect(component?.remainingTimeComponent.timeRemain).toEqual('SYSTEM_ROBOT.EXPIRED');
+ });
+});
+
+
+// mock a TestHostComponent for ListProjectROComponent
+@Component({
+ template: `
+ `
+})
+class TestHostComponent {
+ @ViewChild(RemainingTimeComponent)
+ remainingTimeComponent: RemainingTimeComponent;
+ expires_at: number = -1;
+ deltaTime: number = 100;
+}
diff --git a/src/portal/src/app/shared/components/remaining-time/remaining-time.component.ts b/src/portal/src/app/shared/components/remaining-time/remaining-time.component.ts
new file mode 100644
index 000000000..ca988f757
--- /dev/null
+++ b/src/portal/src/app/shared/components/remaining-time/remaining-time.component.ts
@@ -0,0 +1,83 @@
+// Copyright Project Harbor Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// 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,
+ OnInit,
+ OnDestroy, SimpleChanges, OnChanges,
+} from '@angular/core';
+import { RobotTimeRemainColor } from '../../../base/left-side-nav/system-robot-accounts/system-robot-util';
+const SEC: number = 1000;
+const MIN: number = 60 * 1000;
+const DAY: number = 1000 * 60 * 60 * 24;
+const HOUR: number = 1000 * 60 * 60;
+const WARNING_DAYS = 30;
+@Component({
+ selector: 'app-remaining-time',
+ templateUrl: 'remaining-time.component.html',
+ styleUrls: ['./remaining-time.component.scss']
+})
+export class RemainingTimeComponent implements OnInit, OnDestroy, OnChanges {
+ color: string;
+ timeRemain: string;
+ @Input()
+ timeDiff: number; // the different between server time and local time, unit millisecond, localTime - serverTime
+ @Input()
+ deadline: number; // unit second
+ intelVal: any;
+ constructor() { }
+
+ ngOnInit() {
+ if (!this.intelVal) {
+ this.intelVal = setInterval(() => {
+ this.refreshTimeRemain();
+ }, MIN);
+ }
+ }
+ ngOnDestroy() {
+ if (this.intelVal) {
+ clearInterval(this.intelVal);
+ this.intelVal = null;
+ }
+ }
+ ngOnChanges(changes: SimpleChanges): void {
+ if (changes && changes["timeDiff"] && changes["deadline"]) {
+ this.refreshTimeRemain();
+ }
+ }
+ refreshTimeRemain() {
+ if (this.timeDiff !== null && this.deadline !== null) {
+ if (this.deadline === -1) {
+ this.color = RobotTimeRemainColor.GREEN;
+ this.timeRemain = 'ROBOT_ACCOUNT.NEVER_EXPIRED';
+ return;
+ }
+ const time = new Date(this.deadline * SEC).getTime() - new Date(new Date().getTime() - this.timeDiff).getTime();
+ if (time > 0) {
+ const days = Math.floor(time / DAY);
+ const hours = Math.floor((time % DAY) / HOUR);
+ const minutes = Math.floor((time % HOUR) / MIN);
+ this.timeRemain = `${days}d ${hours}h ${minutes}m`;
+ if (days >= WARNING_DAYS) {
+ this.color = RobotTimeRemainColor.GREEN;
+ } else {
+ this.color = RobotTimeRemainColor.WARNING;
+ }
+ } else {
+ this.color = RobotTimeRemainColor.EXPIRED;
+ this.timeRemain = 'SYSTEM_ROBOT.EXPIRED';
+ }
+ }
+ }
+}
diff --git a/src/portal/src/app/shared/shared.module.ts b/src/portal/src/app/shared/shared.module.ts
index 79dd0a12b..c9c6b8120 100644
--- a/src/portal/src/app/shared/shared.module.ts
+++ b/src/portal/src/app/shared/shared.module.ts
@@ -78,6 +78,7 @@ import localeFr from '@angular/common/locales/fr';
import localePt from '@angular/common/locales/pt-PT';
import localeTr from '@angular/common/locales/tr';
import localeDe from '@angular/common/locales/de';
+import { RemainingTimeComponent } from './components/remaining-time/remaining-time.component';
// add locale data for supported languages ['en-us', 'zh-cn', 'zh-tw', 'es-es', 'fr-fr', 'pt-br', 'tr-tr', 'de-de'];
// en-us defaulted supported
registerLocaleData(zh_cn, 'zh-cn');
@@ -153,7 +154,8 @@ ClarityIcons.add({"robot-head": `
ListChartVersionRoComponent,
DatePickerComponent,
ImageNameInputComponent,
- HarborDatetimePipe
+ HarborDatetimePipe,
+ RemainingTimeComponent
],
exports: [
TranslateModule,
@@ -191,7 +193,8 @@ ClarityIcons.add({"robot-head": `
ListChartVersionRoComponent,
DatePickerComponent,
ImageNameInputComponent,
- HarborDatetimePipe
+ HarborDatetimePipe,
+ RemainingTimeComponent
],
providers: [
{provide: EndpointService, useClass: EndpointDefaultService },
diff --git a/src/portal/src/i18n/lang/de-de-lang.json b/src/portal/src/i18n/lang/de-de-lang.json
index e6b55a5b9..b5f8516cf 100644
--- a/src/portal/src/i18n/lang/de-de-lang.json
+++ b/src/portal/src/i18n/lang/de-de-lang.json
@@ -1704,7 +1704,9 @@
"STOP": "Stop",
"LIST": "List",
"REPOSITORY": "Repository",
- "HELM_LABEL": "Helm Chart Label"
+ "HELM_LABEL": "Helm Chart Label",
+ "EXPIRES_IN": "Expires in",
+ "EXPIRED": "Expired"
},
"ACCESSORY": {
"DELETION_TITLE_ACCESSORY": "Confirm Accessory Deletion",
diff --git a/src/portal/src/i18n/lang/en-us-lang.json b/src/portal/src/i18n/lang/en-us-lang.json
index beba71ec8..004827e81 100644
--- a/src/portal/src/i18n/lang/en-us-lang.json
+++ b/src/portal/src/i18n/lang/en-us-lang.json
@@ -1704,7 +1704,9 @@
"STOP": "Stop",
"LIST": "List",
"REPOSITORY": "Repository",
- "HELM_LABEL": "Helm Chart label"
+ "HELM_LABEL": "Helm Chart label",
+ "EXPIRES_IN": "Expires in",
+ "EXPIRED": "Expired"
},
"ACCESSORY": {
"DELETION_TITLE_ACCESSORY": "Confirm Accessory Deletion",
diff --git a/src/portal/src/i18n/lang/es-es-lang.json b/src/portal/src/i18n/lang/es-es-lang.json
index db864dd31..82179648d 100644
--- a/src/portal/src/i18n/lang/es-es-lang.json
+++ b/src/portal/src/i18n/lang/es-es-lang.json
@@ -1703,7 +1703,9 @@
"STOP": "Stop",
"LIST": "List",
"REPOSITORY": "Repository",
- "HELM_LABEL": "Helm Chart label"
+ "HELM_LABEL": "Helm Chart label",
+ "EXPIRES_IN": "Expires in",
+ "EXPIRED": "Expired"
},
"ACCESSORY": {
"DELETION_TITLE_ACCESSORY": "Confirm Accessory Deletion",
diff --git a/src/portal/src/i18n/lang/fr-fr-lang.json b/src/portal/src/i18n/lang/fr-fr-lang.json
index 040e7df3a..2aa6d6d50 100644
--- a/src/portal/src/i18n/lang/fr-fr-lang.json
+++ b/src/portal/src/i18n/lang/fr-fr-lang.json
@@ -1672,7 +1672,9 @@
"STOP": "Stop",
"LIST": "List",
"REPOSITORY": "Repository",
- "HELM_LABEL": "Helm Chart label"
+ "HELM_LABEL": "Helm Chart label",
+ "EXPIRES_IN": "Expires in",
+ "EXPIRED": "Expired"
},
"ACCESSORY": {
"DELETION_TITLE_ACCESSORY": "Confirm Accessory Deletion",
diff --git a/src/portal/src/i18n/lang/pt-br-lang.json b/src/portal/src/i18n/lang/pt-br-lang.json
index 3a40c1db1..52c63b1da 100644
--- a/src/portal/src/i18n/lang/pt-br-lang.json
+++ b/src/portal/src/i18n/lang/pt-br-lang.json
@@ -1700,7 +1700,9 @@
"STOP": "Parar",
"LIST": "Listar",
"REPOSITORY": "Repositório",
- "HELM_LABEL": "Marcador do Helm Chart"
+ "HELM_LABEL": "Marcador do Helm Chart",
+ "EXPIRES_IN": "Expires in",
+ "EXPIRED": "Expired"
},
"ACCESSORY": {
"DELETION_TITLE_ACCESSORY": "Confirm Accessory Deletion",
diff --git a/src/portal/src/i18n/lang/tr-tr-lang.json b/src/portal/src/i18n/lang/tr-tr-lang.json
index 60c2defec..8faa958a9 100644
--- a/src/portal/src/i18n/lang/tr-tr-lang.json
+++ b/src/portal/src/i18n/lang/tr-tr-lang.json
@@ -1704,7 +1704,9 @@
"STOP": "Stop",
"LIST": "List",
"REPOSITORY": "Repository",
- "HELM_LABEL": "Helm Chart label"
+ "HELM_LABEL": "Helm Chart label",
+ "EXPIRES_IN": "Expires in",
+ "EXPIRED": "Expired"
},
"ACCESSORY": {
"DELETION_TITLE_ACCESSORY": "Confirm Accessory Deletion",
diff --git a/src/portal/src/i18n/lang/zh-cn-lang.json b/src/portal/src/i18n/lang/zh-cn-lang.json
index 436e3cf6e..e991c8c3f 100644
--- a/src/portal/src/i18n/lang/zh-cn-lang.json
+++ b/src/portal/src/i18n/lang/zh-cn-lang.json
@@ -1702,7 +1702,9 @@
"STOP": "停止",
"LIST": "查询",
"REPOSITORY": "仓库",
- "HELM_LABEL": "Helm Chart 标签"
+ "HELM_LABEL": "Helm Chart 标签",
+ "EXPIRES_IN": "有效期剩余",
+ "EXPIRED": "已过期"
},
"ACCESSORY": {
"DELETION_TITLE_ACCESSORY": "删除附件确认",
diff --git a/src/portal/src/i18n/lang/zh-tw-lang.json b/src/portal/src/i18n/lang/zh-tw-lang.json
index f063f52c9..8b9b576b7 100644
--- a/src/portal/src/i18n/lang/zh-tw-lang.json
+++ b/src/portal/src/i18n/lang/zh-tw-lang.json
@@ -1689,7 +1689,9 @@
"STOP": "Stop",
"LIST": "List",
"REPOSITORY": "Repository",
- "HELM_LABEL": "Helm Chart label"
+ "HELM_LABEL": "Helm Chart label",
+ "EXPIRES_IN": "Expires in",
+ "EXPIRED": "Expired"
},
"ACCESSORY": {
"DELETION_TITLE_ACCESSORY": "Confirm Accessory Deletion",