bug fixed

This commit is contained in:
richard-loafle 2020-04-02 15:46:40 +09:00
parent 7a39d2e4aa
commit 07c4b755f8
15 changed files with 358 additions and 135 deletions

35
package-lock.json generated
View File

@ -2402,12 +2402,12 @@
"dev": true "dev": true
}, },
"@ucap/ng-ui-authentication": { "@ucap/ng-ui-authentication": {
"version": "file:pack/ucap-ng-ui-authentication-0.0.8.tgz", "version": "file:pack/ucap-ng-ui-authentication-0.0.13.tgz",
"integrity": "sha512-n6pV113DuSD5TV4jAwrY/JJlhcBtNLHEFTTxrQ8QhFIMz9hgbRC6x4R/LF8q9kzx0BWQcgxGdfgY1oN3YoqGtg==" "integrity": "sha512-TrPEMg6nOJKFCsQN4EGDtA78ugBnhahvDw0pRvs67CFQ28hqQqFdMhuG7Qyl/+L2nJ7XfRZOAgYlEfddDtYEZA=="
}, },
"@ucap/ng-ui-organization": { "@ucap/ng-ui-organization": {
"version": "file:pack/ucap-ng-ui-organization-0.0.1.tgz", "version": "file:pack/ucap-ng-ui-organization-0.0.2.tgz",
"integrity": "sha512-ihbfzCAL6f2+dOnhyjv3u3SP/8LgcXekDBB7Jt0P+4FdtIVM70Z5OjdObNlyi8rld9elc3SiWmpsxXz1cmouXw==", "integrity": "sha512-xywle2jhGaaNxkH+9VLvIOxfFzdLMf5nGP7fqW9gPSZiK51OR5s81UwWoXCeQRfnJuUX+6U97LoY7KAO5c0LLA==",
"dev": true "dev": true
}, },
"@ucap/ng-ui-skin-default": { "@ucap/ng-ui-skin-default": {
@ -2421,29 +2421,10 @@
"dev": true "dev": true
}, },
"@ucap/pi": { "@ucap/pi": {
"version": "0.0.2", "version": "0.0.5",
"resolved": "http://10.81.13.221:8081/nexus/repository/npm-all/@ucap/pi/-/pi-0.0.2.tgz", "resolved": "http://10.81.13.221:8081/nexus/repository/npm-all/@ucap/pi/-/pi-0.0.5.tgz",
"integrity": "sha512-HgCuKMmdWMEhCi4zoPEOd/Ef+Fm7dRdI/66Jzyr2JRbbStAsrO9qIwXlmtTI40Ggy7nCrt1ywRAtV1m1pA2+Ug==", "integrity": "sha512-nWev387pHxeBHtOu0EvRTVQ0/JeJL44Ew0PzQaiqHsC5mghkJ6ok7z22nk9nmuZ7lONxGJmW7CHT8X8lyviZJg==",
"dev": true, "dev": true
"requires": {
"@ucap/api": "^0.0.1",
"@ucap/core": "^0.0.1",
"axios": "^0.19.2",
"crypto-js": "^4.0.0",
"rxjs": "^6.5.4"
},
"dependencies": {
"@ucap/core": {
"version": "0.0.1",
"resolved": "http://10.81.13.221:8081/nexus/repository/npm-all/@ucap/core/-/core-0.0.1.tgz",
"integrity": "sha512-TfQqgu9/Ys0a7wN+3U97ZivUcwF9Ko0uY3qWgyV41MzlCKjigH2L2+hxj6/x9yxXZIK6/ynvVW3RB7x1odR5bQ==",
"dev": true,
"requires": {
"detect-browser": "^5.0.0",
"file-type": "^14.1.4"
}
}
}
}, },
"@ucap/protocol": { "@ucap/protocol": {
"version": "0.0.1", "version": "0.0.1",

View File

@ -170,11 +170,11 @@
"@ucap/ng-store-group": "file:pack/ucap-ng-store-group-0.0.3.tgz", "@ucap/ng-store-group": "file:pack/ucap-ng-store-group-0.0.3.tgz",
"@ucap/ng-store-organization": "file:pack/ucap-ng-store-organization-0.0.3.tgz", "@ucap/ng-store-organization": "file:pack/ucap-ng-store-organization-0.0.3.tgz",
"@ucap/ng-ui": "file:pack/ucap-ng-ui-0.0.3.tgz", "@ucap/ng-ui": "file:pack/ucap-ng-ui-0.0.3.tgz",
"@ucap/ng-ui-authentication": "file:pack/ucap-ng-ui-authentication-0.0.8.tgz", "@ucap/ng-ui-authentication": "file:pack/ucap-ng-ui-authentication-0.0.13.tgz",
"@ucap/ng-ui-organization": "file:pack/ucap-ng-ui-organization-0.0.1.tgz", "@ucap/ng-ui-organization": "file:pack/ucap-ng-ui-organization-0.0.2.tgz",
"@ucap/ng-ui-skin-default": "file:pack/ucap-ng-ui-skin-default-0.0.1.tgz", "@ucap/ng-ui-skin-default": "file:pack/ucap-ng-ui-skin-default-0.0.1.tgz",
"@ucap/ng-web-storage": "file:pack/ucap-ng-web-storage-0.0.1.tgz", "@ucap/ng-web-storage": "file:pack/ucap-ng-web-storage-0.0.1.tgz",
"@ucap/pi": "~0.0.1", "@ucap/pi": "~0.0.5",
"@ucap/protocol": "~0.0.1", "@ucap/protocol": "~0.0.1",
"@ucap/protocol-authentication": "~0.0.1", "@ucap/protocol-authentication": "~0.0.1",
"@ucap/protocol-buddy": "~0.0.1", "@ucap/protocol-buddy": "~0.0.1",

View File

@ -10,10 +10,11 @@ import {
import { StringMap, TOptions } from 'i18next'; import { StringMap, TOptions } from 'i18next';
import { ObjectUtil } from '@ucap/core';
import { I18nService } from '../services/i18n.service'; import { I18nService } from '../services/i18n.service';
import { UCAP_I18N_NAMESPACE } from '../types/token'; import { UCAP_I18N_NAMESPACE } from '../types/token';
import { ObjectUtil } from '../utils/object.util';
@Pipe({ name: 'ucapI18n', pure: false }) @Pipe({ name: 'ucapI18n', pure: false })
export class I18nPipe implements PipeTransform, OnDestroy { export class I18nPipe implements PipeTransform, OnDestroy {

View File

@ -1,83 +0,0 @@
export class ObjectUtil {
static equals(o1: any, o2: any): boolean {
if (o1 === o2) {
return true;
}
if (o1 === null || o2 === null) {
return false;
}
if (o1 !== o1 && o2 !== o2) {
return true; // NaN === NaN
}
const t1 = typeof o1;
const t2 = typeof o2;
let length: number;
let key: any;
let keySet: any;
if (t1 === t2 && t1 === 'object') {
if (Array.isArray(o1)) {
if (!Array.isArray(o2)) {
return false;
}
length = o1.length;
if (length === o2.length) {
for (key = 0; key < length; key++) {
if (!ObjectUtil.equals(o1[key], o2[key])) {
return false;
}
}
return true;
}
} else {
if (Array.isArray(o2)) {
return false;
}
keySet = Object.create(null);
for (key in o1) {
if (o1.hasOwnProperty(key)) {
if (!ObjectUtil.equals(o1[key], o2[key])) {
return false;
}
keySet[key] = true;
}
}
for (key in o2) {
if (!(key in keySet) && typeof o2[key] !== 'undefined') {
return false;
}
}
return true;
}
}
return false;
}
static isDefined(value: any): boolean {
return typeof value !== 'undefined' && value !== null;
}
static isObject(item: any): boolean {
return item && typeof item === 'object' && !Array.isArray(item);
}
static mergeDeep(target: any, source: any): any {
const output = Object.assign({}, target);
if (ObjectUtil.isObject(target) && ObjectUtil.isObject(source)) {
Object.keys(source).forEach((key: any) => {
if (ObjectUtil.isObject(source[key])) {
if (!(key in target)) {
Object.assign(output, { [key]: source[key] });
} else {
output[key] = ObjectUtil.mergeDeep(target[key], source[key]);
}
} else {
Object.assign(output, { [key]: source[key] });
}
});
}
return output;
}
}

View File

@ -4,6 +4,7 @@
"lib": { "lib": {
"entryFile": "src/public-api.ts", "entryFile": "src/public-api.ts",
"umdModuleIds": { "umdModuleIds": {
"moment": "moment",
"@ucap/pi": "@ucap/pi", "@ucap/pi": "@ucap/pi",
"@ucap/ng-i18n": "@ucap/ng-i18n", "@ucap/ng-i18n": "@ucap/ng-i18n",
"@ucap/ng-ui": "@ucap/ng-ui" "@ucap/ng-ui": "@ucap/ng-ui"

View File

@ -1,6 +1,6 @@
{ {
"name": "@ucap/ng-ui-authentication", "name": "@ucap/ng-ui-authentication",
"version": "0.0.8", "version": "0.0.13",
"publishConfig": { "publishConfig": {
"registry": "http://10.81.13.221:8081/nexus/repository/npm-ucap/" "registry": "http://10.81.13.221:8081/nexus/repository/npm-ucap/"
}, },

View File

@ -81,6 +81,7 @@
<mat-error <mat-error
*ngIf=" *ngIf="
companyCodeFormControl.dirty && companyCodeFormControl.dirty &&
companyCodeFormControl.invalid &&
companyCodeFormControl.hasError('required') companyCodeFormControl.hasError('required')
" "
> >
@ -88,32 +89,63 @@
</mat-error> </mat-error>
<mat-error <mat-error
*ngIf=" *ngIf="
loginIdFormControl.dirty && loginIdFormControl.hasError('required') loginIdFormControl.dirty &&
loginIdFormControl.invalid &&
loginIdFormControl.hasError('required')
" "
> >
{{ 'login.errors.requireLoginId' | ucapI18n }} {{ 'login.errors.requireLoginId' | ucapI18n }}
</mat-error> </mat-error>
<mat-error <mat-error
*ngIf=" *ngIf="
loginPwFormControl.dirty && loginPwFormControl.hasError('required') loginPwFormControl.dirty &&
loginPwFormControl.invalid &&
loginPwFormControl.hasError('required')
" "
> >
{{ 'login.errors.requireLoginPw' | ucapI18n }} {{ 'login.errors.requireLoginPw' | ucapI18n }}
</mat-error> </mat-error>
<mat-error *ngIf="loginFailed">
{{ 'login.errors.failed' | ucapI18n }}
</mat-error>
</div> </div>
<button <button
mat-raised-button mat-raised-button
class="submit-button bg-accent-dark" class="submit-button bg-accent-dark"
aria-label="LOG IN" aria-label="LOG IN"
[disabled]="loginForm.invalid || disable" [disabled]="
loginForm.invalid ||
disable ||
(!!loginTry && !!loginTry.remainTimeForNextTry)
"
(click)="onClickLogin()" (click)="onClickLogin()"
> >
<ng-container *ngIf="!processing"> <ng-container
*ngIf="!processing && (!loginTry || !loginTry.remainTimeForNextTry)"
>
{{ 'login.labels.doLogin' | ucapI18n }} {{ 'login.labels.doLogin' | ucapI18n }}
</ng-container> </ng-container>
<mat-spinner *ngIf="processing"> </mat-spinner> <ng-container *ngIf="!!loginTry && !!loginTry.remainTimeForNextTry">
{{ 'login.errors.attemptsExceeded' | ucapI18n }}
(
{{
moment
.utc(
moment
.duration(loginTry.remainTimeForNextTry, 'seconds')
.asMilliseconds()
)
.format('hh:mm:ss')
}}
)
</ng-container>
<mat-spinner
*ngIf="processing && (!loginTry || !loginTry.remainTimeForNextTry)"
>
</mat-spinner>
</button> </button>
</form> </form>

View File

@ -1,3 +1,5 @@
import moment from 'moment';
import { import {
Component, Component,
OnInit, OnInit,
@ -16,6 +18,7 @@ import {
ValidatorFn ValidatorFn
} from '@angular/forms'; } from '@angular/forms';
import { Company } from '@ucap/api-external'; import { Company } from '@ucap/api-external';
import { LoginTry } from '@ucap/pi';
@Component({ @Component({
selector: 'ucap-authentication-login', selector: 'ucap-authentication-login',
@ -41,6 +44,9 @@ export class LoginComponent implements OnInit {
@Input() @Input()
processing = false; processing = false;
@Input()
loginTry: LoginTry;
@Output() @Output()
login = new EventEmitter<{ login = new EventEmitter<{
companyCode: string; companyCode: string;
@ -55,6 +61,9 @@ export class LoginComponent implements OnInit {
companyCodeFormControl = new FormControl(''); companyCodeFormControl = new FormControl('');
loginIdFormControl = new FormControl(''); loginIdFormControl = new FormControl('');
loginPwFormControl = new FormControl(''); loginPwFormControl = new FormControl('');
loginFailed = false;
moment = moment;
constructor( constructor(
private formBuilder: FormBuilder, private formBuilder: FormBuilder,
@ -90,6 +99,7 @@ export class LoginComponent implements OnInit {
loginId: this.loginForm.get('loginIdFormControl').value, loginId: this.loginForm.get('loginIdFormControl').value,
loginPw: this.loginForm.get('loginPwFormControl').value, loginPw: this.loginForm.get('loginPwFormControl').value,
notValid: () => { notValid: () => {
this.loginFailed = true;
this.loginPwElementRef.nativeElement.focus(); this.loginPwElementRef.nativeElement.focus();
} }
}); });

View File

@ -4,6 +4,7 @@
"lib": { "lib": {
"entryFile": "src/public-api.ts", "entryFile": "src/public-api.ts",
"umdModuleIds": { "umdModuleIds": {
"@ucap/core": "@ucap/core",
"@ucap/ng-ui": "@ucap/ng-ui" "@ucap/ng-ui": "@ucap/ng-ui"
} }
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "@ucap/ng-ui-organization", "name": "@ucap/ng-ui-organization",
"version": "0.0.1", "version": "0.0.2",
"publishConfig": { "publishConfig": {
"registry": "http://10.81.13.221:8081/nexus/repository/npm-ucap/" "registry": "http://10.81.13.221:8081/nexus/repository/npm-ucap/"
}, },

View File

@ -6,11 +6,15 @@ import { UiModule } from '@ucap/ng-ui';
import { ModuleConfig } from './config/module-config'; import { ModuleConfig } from './config/module-config';
import { _MODULE_CONFIG } from './config/token'; import { _MODULE_CONFIG } from './config/token';
import { TranslatePipe } from './pipes/translate.pipe';
import { TranslateService } from './services/translate.service';
const COMPONENTS = []; const COMPONENTS = [];
const DIALOGS = []; const DIALOGS = [];
const PIPES = []; const PIPES = [TranslatePipe];
const DIRECTIVES = []; const DIRECTIVES = [];
const SERVICES = []; const SERVICES = [TranslateService];
@NgModule({ @NgModule({
declarations: [], declarations: [],

View File

@ -0,0 +1,121 @@
import {
ChangeDetectorRef,
Injectable,
OnDestroy,
Pipe,
PipeTransform
} from '@angular/core';
import { Subscription } from 'rxjs';
import { ObjectUtil } from '@ucap/core';
import {
TranslateService,
LangChangeEvent
} from '../services/translate.service';
@Injectable()
@Pipe({
name: 'ucapOrganizationTranslate',
pure: false // required to update the value when the promise is resolved
})
export class TranslatePipe implements PipeTransform, OnDestroy {
value = '';
lastTarget: any;
lastKey: string;
lastSeparator: string;
changedLangSubscription: Subscription;
changedDefaultLangSubscription: Subscription;
constructor(
private translateService: TranslateService,
private changeDetectorRef: ChangeDetectorRef
) {}
updateValue(target: any, key: string, separator?: string): void {
try {
const value = this.translateService.get(target, key, separator);
this.value = value;
} catch (error) {
this.value = key;
}
this.lastTarget = target;
this.lastKey = key;
this.changeDetectorRef.markForCheck();
}
transform(target: any, key: string, separator?: string): any {
if (
!target ||
0 === Object.keys(target).length ||
!key ||
0 === key.length
) {
return '';
}
// if we ask another time for the same key, return the last value
if (
ObjectUtil.equals(target, this.lastTarget) &&
ObjectUtil.equals(key, this.lastKey) &&
ObjectUtil.equals(separator, this.lastSeparator)
) {
return this.value;
}
// store the target, in case it changes
this.lastTarget = target;
// store the key, in case it changes
this.lastKey = key;
// store the key, in case it changes
this.lastSeparator = separator;
// set the value
this.updateValue(target, key, separator);
// if there is a subscription to onLangChange, clean it
this._dispose();
// subscribe to onLangChange event, in case the language changes
if (!this.changedLangSubscription) {
this.changedLangSubscription = this.translateService.changedLang.subscribe(
(event: LangChangeEvent) => {
if (this.lastKey) {
this.lastKey = null; // we want to make sure it doesn't return the same value until it's been updated
this.updateValue(target, key, separator);
}
}
);
}
// subscribe to onDefaultLangChange event, in case the default language changes
if (!this.changedDefaultLangSubscription) {
this.changedDefaultLangSubscription = this.translateService.changedDefaultLang.subscribe(
() => {
if (this.lastKey) {
this.lastKey = null; // we want to make sure it doesn't return the same value until it's been updated
this.updateValue(target, key, separator);
}
}
);
}
return this.value;
}
/**
* Clean any existing subscription to change events
*/
private _dispose(): void {
if (!!this.changedLangSubscription) {
this.changedLangSubscription.unsubscribe();
this.changedLangSubscription = undefined;
}
if (!!this.changedDefaultLangSubscription) {
this.changedDefaultLangSubscription.unsubscribe();
this.changedDefaultLangSubscription = undefined;
}
}
ngOnDestroy(): void {
this._dispose();
}
}

View File

@ -0,0 +1,161 @@
import { Injectable, EventEmitter } from '@angular/core';
export interface LangChangeEvent {
lang: string;
}
export interface DefaultLangChangeEvent {
lang: string;
}
@Injectable({
providedIn: 'root'
})
export class TranslateService {
// tslint:disable-next-line: variable-name
private _changedLang: EventEmitter<LangChangeEvent> = new EventEmitter<
LangChangeEvent
>();
// tslint:disable-next-line: variable-name
private _changedDefaultLang: EventEmitter<
DefaultLangChangeEvent
> = new EventEmitter<DefaultLangChangeEvent>();
// tslint:disable-next-line: variable-name
private _defaultLang: string;
// tslint:disable-next-line: variable-name
private _currentLang: string;
/**
* An EventEmitter to listen to lang change events
* onLangChange.subscribe((params: LangChangeEvent) => {
* // do something
* });
*/
get changedLang(): EventEmitter<LangChangeEvent> {
return this._changedLang;
}
/**
* An EventEmitter to listen to default lang change events
* onDefaultLangChange.subscribe((params: DefaultLangChangeEvent) => {
* // do something
* });
*/
get changedDefaultLang() {
return this._changedDefaultLang;
}
/**
* The default lang to fallback when translations are missing on the current lang
*/
get defaultLang(): string {
return this._defaultLang;
}
set defaultLang(defaultLang: string) {
this._defaultLang = defaultLang;
}
/**
* The lang currently used
*/
get currentLang(): string {
return this._currentLang;
}
set currentLang(currentLang: string) {
this._currentLang = currentLang;
}
constructor() {}
/**
* Sets the default language to use as a fallback
*/
public setDefaultLang(lang: string): void {
if (lang === this.defaultLang) {
return;
}
this.changeDefaultLang(lang);
}
/**
* Gets the default language used
*/
public getDefaultLang(): string {
return this.defaultLang;
}
/**
* Changes the lang currently used
*/
public use(lang: string): void {
// don't change the language if the language given is already selected
if (lang === this.currentLang) {
return;
}
this.changeLang(lang);
}
/**
* Gets the translated value of a key (or an array of keys)
* @returns the translated key, or an object of translated keys
*/
public get(target: any, key: string, separator?: string): string {
if (!target || 0 === Object.keys(target).length) {
throw new Error(`Parameter "target" is not valid`);
}
if (!key || 0 === key.length) {
throw new Error(`Parameter "key" required`);
}
if (target instanceof Array) {
const result: string[] = [];
target.forEach(t => {
result.push(this.get(t, key, separator));
});
return result.join(!!separator ? separator : '');
}
const keys = Object.keys(target);
try {
const lang =
this.currentLang.charAt(0).toUpperCase() +
this.currentLang.substring(1);
const langKey = `${key}${lang}`;
if (-1 !== keys.indexOf(langKey)) {
return target[langKey];
}
} catch (error) {}
if (-1 !== keys.indexOf(key)) {
return target[key];
}
throw new Error(`value is not exist`);
}
/**
* Changes the current lang
*/
private changeLang(lang: string): void {
this.currentLang = lang;
this.changedLang.emit({ lang });
// if there is no default lang, use the one that we just set
if (!this.defaultLang) {
this.changeDefaultLang(lang);
}
}
/**
* Changes the default lang
*/
private changeDefaultLang(lang: string): void {
this.defaultLang = lang;
this.changedDefaultLang.emit({ lang });
}
}

View File

@ -4,4 +4,8 @@
export * from './lib/config/module-config'; export * from './lib/config/module-config';
export * from './lib/pipes/translate.pipe';
export * from './lib/services/translate.service';
export * from './lib/organization-ui.module'; export * from './lib/organization-ui.module';

View File

@ -1,17 +1,7 @@
{ {
"extends": "../../tslint.json", "extends": "../../tslint.json",
"rules": { "rules": {
"directive-selector": [ "directive-selector": [true, "attribute", "ucapOrganization", "camelCase"],
true, "component-selector": [true, "element", "ucap-organization", "kebab-case"]
"attribute",
"ucapOrganization",
"camelCase"
],
"component-selector": [
true,
"element",
"ucap-organization",
"kebab-case"
]
} }
} }