mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-29 21:54:13 +01:00
Improve login page for OIDC (#15214)
Signed-off-by: AllForNothing <sshijun@vmware.com>
This commit is contained in:
parent
29ccdff766
commit
bb57264f11
@ -2,55 +2,80 @@
|
|||||||
<global-message [isAppLevel]="true"></global-message>
|
<global-message [isAppLevel]="true"></global-message>
|
||||||
<navigator (showDialogModalAction)="openModal($event)"></navigator>
|
<navigator (showDialogModalAction)="openModal($event)"></navigator>
|
||||||
<search-result></search-result>
|
<search-result></search-result>
|
||||||
<div class="login-wrapper" [ngStyle]="{'background-image': customLoginBgImg? 'url(/images/' + customLoginBgImg + ')': ''}">
|
<div class="login-wrapper"
|
||||||
|
[ngStyle]="{'background-image': customLoginBgImg? 'url(/images/' + customLoginBgImg + ')': ''}">
|
||||||
<form #signInForm="ngForm" class="login">
|
<form #signInForm="ngForm" class="login">
|
||||||
<label class="title"> {{customAppTitle? customAppTitle:(appTitle | translate)}}
|
<span *ngIf="isOidcLoginMode && steps===2" (click)="steps=1" class="back-icon">
|
||||||
|
<clr-icon shape="angle left"></clr-icon>
|
||||||
|
<div class="margin-left-3">{{'SEARCH.BACK' | translate }}</div>
|
||||||
|
</span>
|
||||||
|
<label class="title"> {{customAppTitle ? customAppTitle : (appTitle | translate)}}
|
||||||
</label>
|
</label>
|
||||||
<a href="/c/oidc/login" class="login-oidc" *ngIf="isOidcLoginMode">
|
|
||||||
<button type="button" id="log_oidc" class="btn btn-primary btn-block">
|
|
||||||
<span>{{'BUTTON.LOG_IN_OIDC' | translate }}</span>
|
|
||||||
</button>
|
|
||||||
</a>
|
|
||||||
<div class="login-group">
|
<div class="login-group">
|
||||||
<clr-input-container>
|
<ng-container *ngIf="isOidcLoginMode && steps ===1">
|
||||||
<input clrInput class="username" type="text" required [(ngModel)]="signInCredential.principal" name="login_username" id="login_username"
|
<a href="/c/oidc/login">
|
||||||
placeholder='{{"PLACEHOLDER.SIGN_IN_NAME" | translate}}' #userNameInput='ngModel'>
|
<button type="button" id="log_oidc" class="btn btn-primary btn-block">
|
||||||
<clr-control-error>{{ 'TOOLTIP.SIGN_IN_USERNAME' | translate }}</clr-control-error>
|
<span>{{'BUTTON.LOG_IN_OIDC' | translate }}</span>
|
||||||
</clr-input-container>
|
</button>
|
||||||
<div class="clr-form-control">
|
</a>
|
||||||
<div class="clr-control-container" [class.clr-error] ="passwordInput.invalid && (passwordInput.dirty || passwordInput.touched)">
|
<div class="divider-container mt-1 mb-1">
|
||||||
<div class="clr-input-wrapper">
|
<hr class="divider" size="1" noshade/>
|
||||||
<input class="clr-input pwd-input" [type]="showPwd?'text':'password'" required [(ngModel)]="signInCredential.password" name="login_password" id="login_password"
|
<h4 class="m-0"><span>{{'SIGN_IN.OR' | translate }}</span></h4>
|
||||||
placeholder='{{"PLACEHOLDER.SIGN_IN_PWD" | translate}}' #passwordInput="ngModel">
|
<hr class="divider" size="1" noshade/>
|
||||||
<clr-icon *ngIf="!showPwd" shape="eye" class="pw-eye" (click)="showPwd =!showPwd"></clr-icon>
|
|
||||||
<clr-icon *ngIf="showPwd" shape="eye-hide" class="pw-eye" (click)="showPwd =!showPwd"></clr-icon>
|
|
||||||
<clr-icon class="clr-validate-icon" shape="exclamation-circle"></clr-icon>
|
|
||||||
</div>
|
|
||||||
<clr-control-error *ngIf="passwordInput.invalid && (passwordInput.dirty || passwordInput.touched)">
|
|
||||||
{{ 'TOOLTIP.SIGN_IN_PWD' | translate }}
|
|
||||||
</clr-control-error>
|
|
||||||
</div>
|
</div>
|
||||||
|
<a href="javascript:void(0)" (click)="steps=2">
|
||||||
|
<button type="button" id="login-db" class="btn btn-primary btn-block mt-0">
|
||||||
|
<span>{{'SIGN_IN.VIA_LOCAL_DB' | translate }}</span>
|
||||||
|
</button>
|
||||||
|
</a>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container *ngIf="(!isOidcLoginMode && steps === 1) || (isOidcLoginMode && steps ===2)">
|
||||||
|
<clr-input-container class="mt-3">
|
||||||
|
<input clrInput class="username" type="text" required [(ngModel)]="signInCredential.principal"
|
||||||
|
name="login_username" id="login_username"
|
||||||
|
placeholder='{{"PLACEHOLDER.SIGN_IN_NAME" | translate}}' #userNameInput='ngModel'>
|
||||||
|
<clr-control-error>{{ 'TOOLTIP.SIGN_IN_USERNAME' | translate }}</clr-control-error>
|
||||||
|
</clr-input-container>
|
||||||
|
<div class="clr-form-control">
|
||||||
|
<div class="clr-control-container"
|
||||||
|
[class.clr-error]="passwordInput.invalid && (passwordInput.dirty || passwordInput.touched)">
|
||||||
|
<div class="clr-input-wrapper">
|
||||||
|
<input class="clr-input pwd-input" [type]="showPwd?'text':'password'" required
|
||||||
|
[(ngModel)]="signInCredential.password" name="login_password" id="login_password"
|
||||||
|
placeholder='{{"PLACEHOLDER.SIGN_IN_PWD" | translate}}' #passwordInput="ngModel">
|
||||||
|
<clr-icon *ngIf="!showPwd" shape="eye" class="pw-eye"
|
||||||
|
(click)="showPwd =!showPwd"></clr-icon>
|
||||||
|
<clr-icon *ngIf="showPwd" shape="eye-hide" class="pw-eye"
|
||||||
|
(click)="showPwd =!showPwd"></clr-icon>
|
||||||
|
<clr-icon class="clr-validate-icon" shape="exclamation-circle"></clr-icon>
|
||||||
|
</div>
|
||||||
|
<clr-control-error
|
||||||
|
*ngIf="passwordInput.invalid && (passwordInput.dirty || passwordInput.touched)">
|
||||||
|
{{ 'TOOLTIP.SIGN_IN_PWD' | translate }}
|
||||||
|
</clr-control-error>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="display-flex">
|
||||||
|
<clr-checkbox-wrapper>
|
||||||
|
<input clrCheckbox type="checkbox" id="rememberme" #rememberMeBox
|
||||||
|
(click)="clickRememberMe($event)" [checked]="rememberMe">
|
||||||
|
<label class="reset-label" for="rememberme">{{ 'SIGN_IN.REMEMBER' | translate }}</label>
|
||||||
|
</clr-checkbox-wrapper>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="isError" class="error active">
|
||||||
|
<span *ngIf="isCoreServiceAvailable">{{ 'SIGN_IN.INVALID_MSG' | translate }}</span>
|
||||||
|
<span *ngIf="!isCoreServiceAvailable">{{ 'SIGN_IN.CORE_SERVICE_NOT_AVAILABLE' | translate }}</span>
|
||||||
|
</div>
|
||||||
|
<button [disabled]="isOnGoing || !isValid" type="submit" class="btn btn-primary mt-2" (click)="signIn()"
|
||||||
|
id="log_in">{{ 'BUTTON.LOG_IN' | translate }}</button>
|
||||||
|
<a href="javascript:void(0)" class="signup" (click)="signUp()"
|
||||||
|
*ngIf="selfSignUp">{{ 'BUTTON.SIGN_UP_LINK' | translate }}</a>
|
||||||
|
</ng-container>
|
||||||
|
<div class="more-info" [ngClass]="{'pt-1': (!isOidcLoginMode && steps === 1) || (isOidcLoginMode && steps ===2)}">
|
||||||
|
<a href="https://github.com/goharbor/harbor" target="_blank">{{ 'BUTTON.MORE_INFO' | translate }}</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="display-flex">
|
|
||||||
<clr-checkbox-wrapper>
|
|
||||||
<input clrCheckbox type="checkbox" id="rememberme" #rememberMeBox (click)="clickRememberMe($event)" [checked]="rememberMe">
|
|
||||||
<label class="reset-label" for="rememberme">{{ 'SIGN_IN.REMEMBER' | translate }}</label>
|
|
||||||
</clr-checkbox-wrapper>
|
|
||||||
</div>
|
|
||||||
<div [class.visibility-hidden]="!isError" class="error active">
|
|
||||||
<span *ngIf="isCoreServiceAvailable">{{ 'SIGN_IN.INVALID_MSG' | translate }}</span>
|
|
||||||
<span *ngIf="!isCoreServiceAvailable">{{ 'SIGN_IN.CORE_SERVICE_NOT_AVAILABLE' | translate }}</span>
|
|
||||||
</div>
|
|
||||||
<button [disabled]="isOnGoing || !isValid" type="submit" class="btn btn-primary" (click)="signIn()" id="log_in">{{ 'BUTTON.LOG_IN' | translate }}</button>
|
|
||||||
<a href="javascript:void(0)" class="signup" (click)="signUp()" *ngIf="selfSignUp">{{ 'BUTTON.SIGN_UP_LINK' | translate }}</a>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<a href="https://github.com/goharbor/harbor" target="_blank" class="more-info-link">{{ 'BUTTON.MORE_INFO' | translate }}</a>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<div *ngIf="appConfig.show_popular_repo" id="pop_repo" class="popular-repo-wrapper">
|
|
||||||
<top-repo class="repo-container"></top-repo>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</clr-main-container>
|
</clr-main-container>
|
||||||
<sign-up #signupDialog (userCreation)="handleUserCreation($event)"></sign-up>
|
<sign-up #signupDialog (userCreation)="handleUserCreation($event)"></sign-up>
|
||||||
|
@ -14,31 +14,6 @@
|
|||||||
top: -5px;
|
top: -5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.popular-repo-wrapper {
|
|
||||||
background-color: white;
|
|
||||||
min-height: 100vh;
|
|
||||||
display: flex;
|
|
||||||
flex-grow: 1;
|
|
||||||
margin-top: 24px;
|
|
||||||
justify-content: center;
|
|
||||||
flex-direction: column;
|
|
||||||
height: auto;
|
|
||||||
position: relative;
|
|
||||||
border-left: 1px solid #eee;
|
|
||||||
}
|
|
||||||
|
|
||||||
.repo-container {
|
|
||||||
width: 100%;
|
|
||||||
margin-top: -210px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.more-info-link {
|
|
||||||
position: relative;
|
|
||||||
top: 80px;
|
|
||||||
left: 294px;
|
|
||||||
padding-right: 36px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tm-font {
|
.tm-font {
|
||||||
font-size: 14px !important;
|
font-size: 14px !important;
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -59,10 +34,6 @@
|
|||||||
background:transparent;
|
background:transparent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.login-oidc{
|
|
||||||
margin-top: 50px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.reset-label {
|
.reset-label {
|
||||||
font-size:inherit;
|
font-size:inherit;
|
||||||
color:inherit;
|
color:inherit;
|
||||||
@ -82,3 +53,41 @@
|
|||||||
.pwd-input {
|
.pwd-input {
|
||||||
padding-right: 26px;
|
padding-right: 26px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.divider-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.divider {
|
||||||
|
margin: 0;
|
||||||
|
width: 8.5rem;
|
||||||
|
}
|
||||||
|
.login {
|
||||||
|
padding-bottom: 180px;
|
||||||
|
}
|
||||||
|
.back-icon {
|
||||||
|
position: absolute;
|
||||||
|
top: 1rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
color: #007cbb;
|
||||||
|
font-size: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.margin-left-3 {
|
||||||
|
margin-left: 3px;
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
position: absolute;
|
||||||
|
top: 10rem
|
||||||
|
}
|
||||||
|
.login-group {
|
||||||
|
width: 70%;
|
||||||
|
position: absolute;
|
||||||
|
top: 10rem
|
||||||
|
}
|
||||||
|
.more-info {
|
||||||
|
text-align: right;
|
||||||
|
padding-top: 2rem;
|
||||||
|
}
|
||||||
|
@ -28,6 +28,7 @@ import { AboutDialogComponent } from "../../shared/components/about-dialog/about
|
|||||||
import { CommonRoutes, CONFIG_AUTH_MODE } from "../../shared/entities/shared.const";
|
import { CommonRoutes, CONFIG_AUTH_MODE } from "../../shared/entities/shared.const";
|
||||||
import { SignInCredential } from "./sign-in-credential";
|
import { SignInCredential } from "./sign-in-credential";
|
||||||
import { UserPermissionService } from "../../shared/services";
|
import { UserPermissionService } from "../../shared/services";
|
||||||
|
import {finalize} from "rxjs/operators";
|
||||||
|
|
||||||
// Define status flags for signing in states
|
// Define status flags for signing in states
|
||||||
export const signInStatusNormal = 0;
|
export const signInStatusNormal = 0;
|
||||||
@ -45,7 +46,6 @@ const expireDays = 10;
|
|||||||
export class SignInComponent implements AfterViewChecked, OnInit {
|
export class SignInComponent implements AfterViewChecked, OnInit {
|
||||||
showPwd: boolean = false;
|
showPwd: boolean = false;
|
||||||
redirectUrl: string = "";
|
redirectUrl: string = "";
|
||||||
appConfig: AppConfig = new AppConfig();
|
|
||||||
// Remeber me indicator
|
// Remeber me indicator
|
||||||
rememberMe: boolean = false;
|
rememberMe: boolean = false;
|
||||||
rememberedName: string = "";
|
rememberedName: string = "";
|
||||||
@ -68,6 +68,8 @@ export class SignInComponent implements AfterViewChecked, OnInit {
|
|||||||
password: ""
|
password: ""
|
||||||
};
|
};
|
||||||
isCoreServiceAvailable: boolean = true;
|
isCoreServiceAvailable: boolean = true;
|
||||||
|
steps: number = 1;
|
||||||
|
hasLoadedAppConfig: boolean = false;
|
||||||
constructor(
|
constructor(
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private session: SessionService,
|
private session: SessionService,
|
||||||
@ -88,15 +90,6 @@ export class SignInComponent implements AfterViewChecked, OnInit {
|
|||||||
this.customAppTitle = customSkinObj.loginTitle;
|
this.customAppTitle = customSkinObj.loginTitle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Before login: Make sure the updated configuration can be loaded
|
|
||||||
this.appConfigService.load()
|
|
||||||
.subscribe(updatedConfig => this.appConfig = updatedConfig
|
|
||||||
, error => {
|
|
||||||
// Catch the error
|
|
||||||
console.error("Failed to load bootstrap options with error: ", error);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.route.queryParams
|
this.route.queryParams
|
||||||
.subscribe(params => {
|
.subscribe(params => {
|
||||||
this.redirectUrl = params["redirect_url"] || "";
|
this.redirectUrl = params["redirect_url"] || "";
|
||||||
@ -117,7 +110,7 @@ export class SignInComponent implements AfterViewChecked, OnInit {
|
|||||||
|
|
||||||
// App title
|
// App title
|
||||||
public get appTitle(): string {
|
public get appTitle(): string {
|
||||||
if (this.appConfig && this.appConfig.with_admiral) {
|
if (this.appConfigService.getConfig() && this.appConfigService.getConfig().with_admiral) {
|
||||||
return "APP_TITLE.VIC";
|
return "APP_TITLE.VIC";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,11 +133,11 @@ export class SignInComponent implements AfterViewChecked, OnInit {
|
|||||||
|
|
||||||
// Whether show the 'sign up' link
|
// Whether show the 'sign up' link
|
||||||
public get selfSignUp(): boolean {
|
public get selfSignUp(): boolean {
|
||||||
return this.appConfig.auth_mode === CONFIG_AUTH_MODE.DB_AUTH
|
return this.appConfigService.getConfig() && this.appConfigService.getConfig().auth_mode === CONFIG_AUTH_MODE.DB_AUTH
|
||||||
&& this.appConfig.self_registration;
|
&& this.appConfigService.getConfig().self_registration;
|
||||||
}
|
}
|
||||||
public get isOidcLoginMode(): boolean {
|
public get isOidcLoginMode(): boolean {
|
||||||
return this.appConfig.auth_mode === CONFIG_AUTH_MODE.OIDC_AUTH;
|
return this.appConfigService.getConfig() && this.appConfigService.getConfig().auth_mode === CONFIG_AUTH_MODE.OIDC_AUTH;
|
||||||
}
|
}
|
||||||
clickRememberMe($event: any): void {
|
clickRememberMe($event: any): void {
|
||||||
if ($event && $event.target) {
|
if ($event && $event.target) {
|
||||||
@ -261,11 +254,7 @@ export class SignInComponent implements AfterViewChecked, OnInit {
|
|||||||
|
|
||||||
// after login successfully: Make sure the updated configuration can be loaded
|
// after login successfully: Make sure the updated configuration can be loaded
|
||||||
this.appConfigService.load()
|
this.appConfigService.load()
|
||||||
.subscribe(updatedConfig => this.appConfig = updatedConfig
|
.subscribe();
|
||||||
, error => {
|
|
||||||
// Catch the error
|
|
||||||
console.error("Failed to load bootstrap options with error: ", error);
|
|
||||||
});
|
|
||||||
}, error => {
|
}, error => {
|
||||||
// 403 oidc login no body;
|
// 403 oidc login no body;
|
||||||
if (this.isOidcLoginMode && error && error.status === 403) {
|
if (this.isOidcLoginMode && error && error.status === 403) {
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
"INVALID_MSG": "Falscher Nutzername oder Passwort.",
|
"INVALID_MSG": "Falscher Nutzername oder Passwort.",
|
||||||
"FORGOT_PWD": "Passwort vergessen",
|
"FORGOT_PWD": "Passwort vergessen",
|
||||||
"HEADER_LINK": "Einloggen",
|
"HEADER_LINK": "Einloggen",
|
||||||
|
"OR": "OR",
|
||||||
|
"VIA_LOCAL_DB": "LOGIN VIA LOCAL DB",
|
||||||
"CORE_SERVICE_NOT_AVAILABLE": "Core Service ist nicht verfügbar"
|
"CORE_SERVICE_NOT_AVAILABLE": "Core Service ist nicht verfügbar"
|
||||||
},
|
},
|
||||||
"SIGN_UP": {
|
"SIGN_UP": {
|
||||||
|
@ -14,7 +14,9 @@
|
|||||||
"INVALID_MSG": "Invalid user name or password.",
|
"INVALID_MSG": "Invalid user name or password.",
|
||||||
"FORGOT_PWD": "Forgot password",
|
"FORGOT_PWD": "Forgot password",
|
||||||
"HEADER_LINK": "Sign In",
|
"HEADER_LINK": "Sign In",
|
||||||
"CORE_SERVICE_NOT_AVAILABLE": "Core service is not available."
|
"CORE_SERVICE_NOT_AVAILABLE": "Core service is not available.",
|
||||||
|
"OR": "OR",
|
||||||
|
"VIA_LOCAL_DB": "LOGIN VIA LOCAL DB"
|
||||||
},
|
},
|
||||||
"SIGN_UP": {
|
"SIGN_UP": {
|
||||||
"TITLE": "Sign Up"
|
"TITLE": "Sign Up"
|
||||||
|
@ -14,7 +14,9 @@
|
|||||||
"INVALID_MSG": "Nombre o contraseña no válidos.",
|
"INVALID_MSG": "Nombre o contraseña no válidos.",
|
||||||
"FORGOT_PWD": "Olvidé mi contraseña",
|
"FORGOT_PWD": "Olvidé mi contraseña",
|
||||||
"HEADER_LINK": "Identificarse",
|
"HEADER_LINK": "Identificarse",
|
||||||
"CORE_SERVICE_NOT_AVAILABLE": "Core service is not available."
|
"CORE_SERVICE_NOT_AVAILABLE": "Core service is not available.",
|
||||||
|
"OR": "OR",
|
||||||
|
"VIA_LOCAL_DB": "LOGIN VIA LOCAL DB"
|
||||||
},
|
},
|
||||||
"SIGN_UP": {
|
"SIGN_UP": {
|
||||||
"TITLE": "Registrarse"
|
"TITLE": "Registrarse"
|
||||||
|
@ -14,7 +14,9 @@
|
|||||||
"INVALID_MSG": "Nom d'utilisateur ou mot de passe invalide.",
|
"INVALID_MSG": "Nom d'utilisateur ou mot de passe invalide.",
|
||||||
"FORGOT_PWD": "Mot de passe oublié",
|
"FORGOT_PWD": "Mot de passe oublié",
|
||||||
"HEADER_LINK": "S'identifier",
|
"HEADER_LINK": "S'identifier",
|
||||||
"CORE_SERVICE_NOT_AVAILABLE": "Core service is not available."
|
"CORE_SERVICE_NOT_AVAILABLE": "Core service is not available.",
|
||||||
|
"OR": "OR",
|
||||||
|
"VIA_LOCAL_DB": "LOGIN VIA LOCAL DB"
|
||||||
},
|
},
|
||||||
"SIGN_UP": {
|
"SIGN_UP": {
|
||||||
"TITLE": "S'inscrire"
|
"TITLE": "S'inscrire"
|
||||||
|
@ -14,7 +14,9 @@
|
|||||||
"INVALID_MSG": "Usuário ou senha inválidos",
|
"INVALID_MSG": "Usuário ou senha inválidos",
|
||||||
"FORGOT_PWD": "Esqueci a senha",
|
"FORGOT_PWD": "Esqueci a senha",
|
||||||
"HEADER_LINK": "Logar-se",
|
"HEADER_LINK": "Logar-se",
|
||||||
"CORE_SERVICE_NOT_AVAILABLE": "Core service is not available."
|
"CORE_SERVICE_NOT_AVAILABLE": "Core service is not available.",
|
||||||
|
"OR": "OR",
|
||||||
|
"VIA_LOCAL_DB": "LOGIN VIA LOCAL DB"
|
||||||
},
|
},
|
||||||
"SIGN_UP": {
|
"SIGN_UP": {
|
||||||
"TITLE": "Registrar-se"
|
"TITLE": "Registrar-se"
|
||||||
|
@ -14,7 +14,9 @@
|
|||||||
"INVALID_MSG": "Geçersiz kullanıcı adı veya şifre.",
|
"INVALID_MSG": "Geçersiz kullanıcı adı veya şifre.",
|
||||||
"FORGOT_PWD": "Parolamı Unuttum",
|
"FORGOT_PWD": "Parolamı Unuttum",
|
||||||
"HEADER_LINK": "Oturum aç",
|
"HEADER_LINK": "Oturum aç",
|
||||||
"CORE_SERVICE_NOT_AVAILABLE": "Core service is not available."
|
"CORE_SERVICE_NOT_AVAILABLE": "Core service is not available.",
|
||||||
|
"OR": "OR",
|
||||||
|
"VIA_LOCAL_DB": "LOGIN VIA LOCAL DB"
|
||||||
},
|
},
|
||||||
"SIGN_UP": {
|
"SIGN_UP": {
|
||||||
"TITLE": "Kayıt ol"
|
"TITLE": "Kayıt ol"
|
||||||
|
@ -14,7 +14,9 @@
|
|||||||
"INVALID_MSG": "用户名或者密码不正确。",
|
"INVALID_MSG": "用户名或者密码不正确。",
|
||||||
"FORGOT_PWD": "忘记密码",
|
"FORGOT_PWD": "忘记密码",
|
||||||
"HEADER_LINK": "登录",
|
"HEADER_LINK": "登录",
|
||||||
"CORE_SERVICE_NOT_AVAILABLE": "核心服务不可用。"
|
"CORE_SERVICE_NOT_AVAILABLE": "核心服务不可用。",
|
||||||
|
"OR": "或",
|
||||||
|
"VIA_LOCAL_DB": "通过本地数据库登录"
|
||||||
},
|
},
|
||||||
"SIGN_UP": {
|
"SIGN_UP": {
|
||||||
"TITLE": "注册"
|
"TITLE": "注册"
|
||||||
|
@ -14,7 +14,9 @@
|
|||||||
"INVALID_MSG": "用戶名或者密碼不正確。",
|
"INVALID_MSG": "用戶名或者密碼不正確。",
|
||||||
"FORGOT_PWD": "忘記密碼",
|
"FORGOT_PWD": "忘記密碼",
|
||||||
"HEADER_LINK": "登錄",
|
"HEADER_LINK": "登錄",
|
||||||
"CORE_SERVICE_NOT_AVAILABLE": "Core service is not available."
|
"CORE_SERVICE_NOT_AVAILABLE": "Core service is not available.",
|
||||||
|
"OR": "OR",
|
||||||
|
"VIA_LOCAL_DB": "LOGIN VIA LOCAL DB"
|
||||||
},
|
},
|
||||||
"SIGN_UP": {
|
"SIGN_UP": {
|
||||||
"TITLE": "註冊"
|
"TITLE": "註冊"
|
||||||
|
Loading…
Reference in New Issue
Block a user