diff --git a/src/portal/src/app/config/auth/config-auth.component.html b/src/portal/src/app/config/auth/config-auth.component.html
index a5d39bceea..d28fec913f 100644
--- a/src/portal/src/app/config/auth/config-auth.component.html
+++ b/src/portal/src/app/config/auth/config-auth.component.html
@@ -402,6 +402,7 @@
@@ -414,9 +415,9 @@
-
+ [disabled]="!currentConfig.oidc_auto_onboard.value || disabled(currentConfig.oidc_user_claim)" pattern="^[a-zA-Z0-9_-]*$">
{{ 'CONFIG.OIDC.OIDC_REDIREC_URL' | translate}}
{{redirectUrl}}/c/oidc/callback
@@ -431,4 +432,4 @@
-
\ No newline at end of file
+
diff --git a/src/portal/src/app/config/auth/config-auth.component.ts b/src/portal/src/app/config/auth/config-auth.component.ts
index 24fce60100..6086bb5dd4 100644
--- a/src/portal/src/app/config/auth/config-auth.component.ts
+++ b/src/portal/src/app/config/auth/config-auth.component.ts
@@ -263,5 +263,9 @@ export class ConfigurationAuthComponent implements OnChanges, OnInit {
console.error('Nothing changed');
}
}
-
+ changeAutoOnBoard() {
+ if (!this.currentConfig.oidc_auto_onboard.value) {
+ this.currentConfig.oidc_user_claim.value = null;
+ }
+ }
}
diff --git a/src/portal/src/app/distribution/distribution-instances/distribution-instances.component.html b/src/portal/src/app/distribution/distribution-instances/distribution-instances.component.html
index 40a041cdf6..6114924ad7 100644
--- a/src/portal/src/app/distribution/distribution-instances/distribution-instances.component.html
+++ b/src/portal/src/app/distribution/distribution-instances/distribution-instances.component.html
@@ -80,33 +80,6 @@
{{ instance.endpoint }}
{{ instance.vendor }}
-
-
-
-
-
-
-
-
- {{'DISTRIBUTION.NAME' | translate}}:
- {{providerMap[instance.vendor].name}}
-
-
-
- {{'DISTRIBUTION.MAINTAINER' | translate}}:
- {{providerMap[instance.vendor].maintainers?.join(',')}}
-
-
-
-
- {{'DISTRIBUTION.VERSION' | translate}}:
- {{providerMap[instance.vendor].version}}
-
-
-
diff --git a/src/portal/src/app/project/repository/repository-gridview.component.html b/src/portal/src/app/project/repository/repository-gridview.component.html
index 3085ba0ff2..a650b07d21 100644
--- a/src/portal/src/app/project/repository/repository-gridview.component.html
+++ b/src/portal/src/app/project/repository/repository-gridview.component.html
@@ -7,7 +7,7 @@
{{'CONFIG.REGISTRY_CERTIFICATE' | translate | uppercase}}
-
+
diff --git a/src/portal/src/app/project/repository/repository-gridview.component.ts b/src/portal/src/app/project/repository/repository-gridview.component.ts
index bb32d4bdda..81e46eb60b 100644
--- a/src/portal/src/app/project/repository/repository-gridview.component.ts
+++ b/src/portal/src/app/project/repository/repository-gridview.component.ts
@@ -93,6 +93,7 @@ export class RepositoryGridviewComponent implements OnChanges, OnInit, OnDestroy
@ViewChild(FilterComponent, {static: true})
filterComponent: FilterComponent;
searchSub: Subscription;
+ isProxyCacheProject: boolean = false;
constructor(@Inject(SERVICE_CONFIG) private configInfo: IServiceConfig,
private errorHandlerService: ErrorHandler,
@@ -139,6 +140,9 @@ export class RepositoryGridviewComponent implements OnChanges, OnInit, OnDestroy
let pro: Project = resolverData['projectResolver'];
this.hasProjectAdminRole = pro.has_project_admin_role;
this.projectName = pro.name;
+ if (pro.registry_id) {
+ this.isProxyCacheProject = true;
+ }
}
this.hasSignedIn = this.session.getCurrentUser() !== null;
// Get system info for tag views
diff --git a/src/portal/src/app/sign-in/sign-in.component.html b/src/portal/src/app/sign-in/sign-in.component.html
index bb64ede270..8dd0ed5642 100644
--- a/src/portal/src/app/sign-in/sign-in.component.html
+++ b/src/portal/src/app/sign-in/sign-in.component.html
@@ -29,7 +29,8 @@
- {{ 'SIGN_IN.INVALID_MSG' | translate }}
+ {{ 'SIGN_IN.INVALID_MSG' | translate }}
+ {{ 'SIGN_IN.CORE_SERVICE_NOT_AVAILABLE' | translate }}
{{ 'BUTTON.SIGN_UP_LINK' | translate }}
@@ -44,4 +45,4 @@
-
\ No newline at end of file
+
diff --git a/src/portal/src/app/sign-in/sign-in.component.spec.ts b/src/portal/src/app/sign-in/sign-in.component.spec.ts
index db2bfe9521..90b1f064f4 100644
--- a/src/portal/src/app/sign-in/sign-in.component.spec.ts
+++ b/src/portal/src/app/sign-in/sign-in.component.spec.ts
@@ -1,4 +1,4 @@
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { async, ComponentFixture, getTestBed, inject, TestBed } from '@angular/core/testing';
import { SignInComponent } from './sign-in.component';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { RouterTestingModule } from '@angular/router/testing';
@@ -10,11 +10,18 @@ import { CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA } from '@angular/core';
import { ClarityModule } from "@clr/angular";
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { of } from "rxjs";
+import { throwError as observableThrowError } from 'rxjs/internal/observable/throwError';
+import { HttpErrorResponse } from '@angular/common/http';
+import { HttpClientTestingModule } from '@angular/common/http/testing';
describe('SignInComponent', () => {
let component: SignInComponent;
let fixture: ComponentFixture;
-
+ const mockedSessionService = {
+ signIn() {
+ return of(true);
+ }
+ };
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
@@ -22,12 +29,13 @@ describe('SignInComponent', () => {
RouterTestingModule,
ClarityModule,
FormsModule,
- ReactiveFormsModule
+ ReactiveFormsModule,
+ HttpClientTestingModule
],
declarations: [SignInComponent],
providers: [
TranslateService,
- { provide: SessionService, useValue: null },
+ { provide: SessionService, useValue: mockedSessionService},
{
provide: AppConfigService, useValue: {
load: function () {
@@ -68,4 +76,44 @@ describe('SignInComponent', () => {
it('should create', () => {
expect(component).toBeTruthy();
});
+
+ it('should show core service is not available', async () => {
+ expect(component).toBeTruthy();
+ const sessionService = TestBed.get(SessionService);
+ const spy: jasmine.Spy = spyOn(sessionService, "signIn").and.returnValue(observableThrowError( new HttpErrorResponse({
+ error: 'test 501 error',
+ status: 501
+ })));
+ signIn();
+ fixture.detectChanges();
+ await fixture.whenStable();
+ expect(spy.calls.count()).toEqual(1);
+ const errorSpan: HTMLSpanElement = fixture.nativeElement.querySelector(".error>span");
+ expect(errorSpan.innerText).toEqual('SIGN_IN.CORE_SERVICE_NOT_AVAILABLE');
+ });
+ it('should show invalid username or password', async () => {
+ expect(component).toBeTruthy();
+ const sessionService = TestBed.get(SessionService);
+ const spy: jasmine.Spy = spyOn(sessionService, "signIn").and.returnValue(observableThrowError( new HttpErrorResponse({
+ error: 'test 404 error',
+ status: 404,
+ statusText: 'Not Found'
+ })));
+ signIn();
+ fixture.detectChanges();
+ await fixture.whenStable();
+ expect(spy.calls.count()).toEqual(1);
+ const errorSpan: HTMLSpanElement = fixture.nativeElement.querySelector(".error>span");
+ expect(errorSpan.innerText).toEqual('SIGN_IN.INVALID_MSG');
+ });
+ function signIn() {
+ const nameInput: HTMLInputElement = fixture.nativeElement.querySelector("#login_username");
+ nameInput.value = "admin";
+ nameInput.dispatchEvent(new Event('input'));
+ const passwordInput: HTMLInputElement = fixture.nativeElement.querySelector("#login_password");
+ passwordInput.value = "Harbor12345";
+ passwordInput.dispatchEvent(new Event('input'));
+ const signButton: HTMLAnchorElement = fixture.nativeElement.querySelector("#log_in");
+ signButton.click();
+ }
});
diff --git a/src/portal/src/app/sign-in/sign-in.component.ts b/src/portal/src/app/sign-in/sign-in.component.ts
index 1dc9fa304f..d0ed37b245 100644
--- a/src/portal/src/app/sign-in/sign-in.component.ts
+++ b/src/portal/src/app/sign-in/sign-in.component.ts
@@ -66,7 +66,7 @@ export class SignInComponent implements AfterViewChecked, OnInit {
principal: "",
password: ""
};
-
+ isCoreServiceAvailable: boolean = true;
constructor(
private router: Router,
private session: SessionService,
@@ -254,6 +254,7 @@ export class SignInComponent implements AfterViewChecked, OnInit {
} else {
this.router.navigateByUrl(this.redirectUrl);
}
+ this.isCoreServiceAvailable = true;
}, error => {
// 403 oidc login no body;
if (this.isOidcLoginMode && error && error.status === 403) {
@@ -265,6 +266,10 @@ export class SignInComponent implements AfterViewChecked, OnInit {
return;
} catch (error) { }
}
+ // core service is not available for error code 5xx
+ if (error && /5[0-9][0-9]/.test(error.status)) {
+ this.isCoreServiceAvailable = false;
+ }
this.handleError(error);
});
}
diff --git a/src/portal/src/i18n/lang/en-us-lang.json b/src/portal/src/i18n/lang/en-us-lang.json
index 661d7b3457..6ba6476e1e 100644
--- a/src/portal/src/i18n/lang/en-us-lang.json
+++ b/src/portal/src/i18n/lang/en-us-lang.json
@@ -13,7 +13,8 @@
"REMEMBER": "Remember me",
"INVALID_MSG": "Invalid user name or password.",
"FORGOT_PWD": "Forgot password",
- "HEADER_LINK": "Sign In"
+ "HEADER_LINK": "Sign In",
+ "CORE_SERVICE_NOT_AVAILABLE": "Core service is not available."
},
"SIGN_UP": {
"TITLE": "Sign Up"
@@ -247,7 +248,7 @@
"QUOTA_UNLIMIT_TIP": "For unlimited quota enter '-1'.",
"TYPE": "Type",
"PROXY_CACHE": "Proxy Cache",
- "PROXY_CACHE_TOOLTIP": "Enable this to allow this project to act as a pull-through cache for a particular namespace within a target registry. Harbor can only act a proxy for DockerHub and Harbor registries.",
+ "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 and Harbor registries.",
"ENDPOINT": "Endpoint",
"PROXY_CACHE_ENDPOINT": "Proxy Cache Endpoint"
},
diff --git a/src/portal/src/i18n/lang/es-es-lang.json b/src/portal/src/i18n/lang/es-es-lang.json
index 7521d58a90..55cf881459 100644
--- a/src/portal/src/i18n/lang/es-es-lang.json
+++ b/src/portal/src/i18n/lang/es-es-lang.json
@@ -13,7 +13,8 @@
"REMEMBER": "Recordarme",
"INVALID_MSG": "Nombre o contraseña no válidos.",
"FORGOT_PWD": "Olvidé mi contraseña",
- "HEADER_LINK": "Identificarse"
+ "HEADER_LINK": "Identificarse",
+ "CORE_SERVICE_NOT_AVAILABLE": "Core service is not available."
},
"SIGN_UP": {
"TITLE": "Registrarse"
@@ -248,7 +249,7 @@
"QUOTA_UNLIMIT_TIP": "For unlimited quota enter '-1'.",
"TYPE": "Type",
"PROXY_CACHE": "Proxy Cache",
- "PROXY_CACHE_TOOLTIP": "Enable this to allow this project to act as a pull-through cache for a particular namespace within a target registry. Harbor can only act a proxy for DockerHub and Harbor registries.",
+ "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 and Harbor registries.",
"ENDPOINT": "Endpoint",
"PROXY_CACHE_ENDPOINT": "Proxy Cache Endpoint"
},
diff --git a/src/portal/src/i18n/lang/fr-fr-lang.json b/src/portal/src/i18n/lang/fr-fr-lang.json
index ecefc6f0c5..4767ca6378 100644
--- a/src/portal/src/i18n/lang/fr-fr-lang.json
+++ b/src/portal/src/i18n/lang/fr-fr-lang.json
@@ -13,7 +13,8 @@
"REMEMBER": "Se souvenir de moi",
"INVALID_MSG": "Nom d'utilisateur ou mot de passe invalide.",
"FORGOT_PWD": "Mot de passe oublié",
- "HEADER_LINK": "S'identifier"
+ "HEADER_LINK": "S'identifier",
+ "CORE_SERVICE_NOT_AVAILABLE": "Core service is not available."
},
"SIGN_UP": {
"TITLE": "S'inscrire"
@@ -241,7 +242,7 @@
"QUOTA_UNLIMIT_TIP": "For unlimited quota enter '-1'.",
"TYPE": "Type",
"PROXY_CACHE": "Proxy Cache",
- "PROXY_CACHE_TOOLTIP": "Enable this to allow this project to act as a pull-through cache for a particular namespace within a target registry. Harbor can only act a proxy for DockerHub and Harbor registries.",
+ "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 and Harbor registries.",
"ENDPOINT": "Endpoint",
"PROXY_CACHE_ENDPOINT": "Proxy Cache Endpoint"
},
diff --git a/src/portal/src/i18n/lang/pt-br-lang.json b/src/portal/src/i18n/lang/pt-br-lang.json
index cec83fb1f1..34dd093861 100644
--- a/src/portal/src/i18n/lang/pt-br-lang.json
+++ b/src/portal/src/i18n/lang/pt-br-lang.json
@@ -13,7 +13,8 @@
"REMEMBER": "Lembrar-se de mim",
"INVALID_MSG": "Usuário ou senha inválidos",
"FORGOT_PWD": "Esqueci a senha",
- "HEADER_LINK": "Logar-se"
+ "HEADER_LINK": "Logar-se",
+ "CORE_SERVICE_NOT_AVAILABLE": "Core service is not available."
},
"SIGN_UP": {
"TITLE": "Registrar-se"
@@ -245,7 +246,7 @@
"QUOTA_UNLIMIT_TIP": "For unlimited quota enter '-1'.",
"TYPE": "Type",
"PROXY_CACHE": "Proxy Cache",
- "PROXY_CACHE_TOOLTIP": "Enable this to allow this project to act as a pull-through cache for a particular namespace within a target registry. Harbor can only act a proxy for DockerHub and Harbor registries.",
+ "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 and Harbor registries.",
"ENDPOINT": "Endpoint",
"PROXY_CACHE_ENDPOINT": "Proxy Cache Endpoint"
},
diff --git a/src/portal/src/i18n/lang/tr-tr-lang.json b/src/portal/src/i18n/lang/tr-tr-lang.json
index 60833b7a65..6976f6585c 100644
--- a/src/portal/src/i18n/lang/tr-tr-lang.json
+++ b/src/portal/src/i18n/lang/tr-tr-lang.json
@@ -13,7 +13,8 @@
"REMEMBER": "Beni Hatırla",
"INVALID_MSG": "Geçersiz kullanıcı adı veya şifre.",
"FORGOT_PWD": "Parolamı Unuttum",
- "HEADER_LINK": "Oturum aç"
+ "HEADER_LINK": "Oturum aç",
+ "CORE_SERVICE_NOT_AVAILABLE": "Core service is not available."
},
"SIGN_UP": {
"TITLE": "Kayıt ol"
@@ -247,7 +248,7 @@
"QUOTA_UNLIMIT_TIP": "Bu kotayı sınırsız istiyorsanız, lütfen -1 girin.",
"TYPE": "Type",
"PROXY_CACHE": "Proxy Cache",
- "PROXY_CACHE_TOOLTIP": "Enable this to allow this project to act as a pull-through cache for a particular namespace within a target registry. Harbor can only act a proxy for DockerHub and Harbor registries.",
+ "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 and Harbor registries.",
"ENDPOINT": "Endpoint",
"PROXY_CACHE_ENDPOINT": "Proxy Cache Endpoint"
},
diff --git a/src/portal/src/i18n/lang/zh-cn-lang.json b/src/portal/src/i18n/lang/zh-cn-lang.json
index 770b877377..6835a31e1a 100644
--- a/src/portal/src/i18n/lang/zh-cn-lang.json
+++ b/src/portal/src/i18n/lang/zh-cn-lang.json
@@ -13,7 +13,8 @@
"REMEMBER": "记住我",
"INVALID_MSG": "用户名或者密码不正确。",
"FORGOT_PWD": "忘记密码",
- "HEADER_LINK": "登录"
+ "HEADER_LINK": "登录",
+ "CORE_SERVICE_NOT_AVAILABLE": "核心服务不可用。"
},
"SIGN_UP": {
"TITLE": "注册"
diff --git a/src/portal/src/i18n/lang/zh-tw-lang.json b/src/portal/src/i18n/lang/zh-tw-lang.json
index 1374c74c57..80542a1208 100644
--- a/src/portal/src/i18n/lang/zh-tw-lang.json
+++ b/src/portal/src/i18n/lang/zh-tw-lang.json
@@ -13,7 +13,8 @@
"REMEMBER": "記住我",
"INVALID_MSG": "用戶名或者密碼不正確。",
"FORGOT_PWD": "忘記密碼",
- "HEADER_LINK": "登錄"
+ "HEADER_LINK": "登錄",
+ "CORE_SERVICE_NOT_AVAILABLE": "Core service is not available."
},
"SIGN_UP": {
"TITLE": "註冊"
@@ -244,7 +245,7 @@
"QUOTA_UNLIMIT_TIP": "如果你想要對存儲不設置上限,請輸入-1。",
"TYPE": "Type",
"PROXY_CACHE": "Proxy Cache",
- "PROXY_CACHE_TOOLTIP": "Enable this to allow this project to act as a pull-through cache for a particular namespace within a target registry. Harbor can only act a proxy for DockerHub and Harbor registries.",
+ "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 and Harbor registries.",
"ENDPOINT": "Endpoint",
"PROXY_CACHE_ENDPOINT": "Proxy Cache Endpoint"
},