diff --git a/package-lock.json b/package-lock.json
index f77c624..34a4fcd 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2402,12 +2402,12 @@
"dev": true
},
"@ucap/ng-ui-authentication": {
- "version": "file:pack/ucap-ng-ui-authentication-0.0.8.tgz",
- "integrity": "sha512-n6pV113DuSD5TV4jAwrY/JJlhcBtNLHEFTTxrQ8QhFIMz9hgbRC6x4R/LF8q9kzx0BWQcgxGdfgY1oN3YoqGtg=="
+ "version": "file:pack/ucap-ng-ui-authentication-0.0.13.tgz",
+ "integrity": "sha512-TrPEMg6nOJKFCsQN4EGDtA78ugBnhahvDw0pRvs67CFQ28hqQqFdMhuG7Qyl/+L2nJ7XfRZOAgYlEfddDtYEZA=="
},
"@ucap/ng-ui-organization": {
- "version": "file:pack/ucap-ng-ui-organization-0.0.1.tgz",
- "integrity": "sha512-ihbfzCAL6f2+dOnhyjv3u3SP/8LgcXekDBB7Jt0P+4FdtIVM70Z5OjdObNlyi8rld9elc3SiWmpsxXz1cmouXw==",
+ "version": "file:pack/ucap-ng-ui-organization-0.0.2.tgz",
+ "integrity": "sha512-xywle2jhGaaNxkH+9VLvIOxfFzdLMf5nGP7fqW9gPSZiK51OR5s81UwWoXCeQRfnJuUX+6U97LoY7KAO5c0LLA==",
"dev": true
},
"@ucap/ng-ui-skin-default": {
@@ -2421,29 +2421,10 @@
"dev": true
},
"@ucap/pi": {
- "version": "0.0.2",
- "resolved": "http://10.81.13.221:8081/nexus/repository/npm-all/@ucap/pi/-/pi-0.0.2.tgz",
- "integrity": "sha512-HgCuKMmdWMEhCi4zoPEOd/Ef+Fm7dRdI/66Jzyr2JRbbStAsrO9qIwXlmtTI40Ggy7nCrt1ywRAtV1m1pA2+Ug==",
- "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"
- }
- }
- }
+ "version": "0.0.5",
+ "resolved": "http://10.81.13.221:8081/nexus/repository/npm-all/@ucap/pi/-/pi-0.0.5.tgz",
+ "integrity": "sha512-nWev387pHxeBHtOu0EvRTVQ0/JeJL44Ew0PzQaiqHsC5mghkJ6ok7z22nk9nmuZ7lONxGJmW7CHT8X8lyviZJg==",
+ "dev": true
},
"@ucap/protocol": {
"version": "0.0.1",
diff --git a/package.json b/package.json
index f059213..d75ee58 100644
--- a/package.json
+++ b/package.json
@@ -170,11 +170,11 @@
"@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-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-organization": "file:pack/ucap-ng-ui-organization-0.0.1.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.2.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/pi": "~0.0.1",
+ "@ucap/pi": "~0.0.5",
"@ucap/protocol": "~0.0.1",
"@ucap/protocol-authentication": "~0.0.1",
"@ucap/protocol-buddy": "~0.0.1",
diff --git a/projects/i18n/src/lib/pipes/i18n.pipe.ts b/projects/i18n/src/lib/pipes/i18n.pipe.ts
index 5552c2f..1dc5863 100644
--- a/projects/i18n/src/lib/pipes/i18n.pipe.ts
+++ b/projects/i18n/src/lib/pipes/i18n.pipe.ts
@@ -10,10 +10,11 @@ import {
import { StringMap, TOptions } from 'i18next';
+import { ObjectUtil } from '@ucap/core';
+
import { I18nService } from '../services/i18n.service';
import { UCAP_I18N_NAMESPACE } from '../types/token';
-import { ObjectUtil } from '../utils/object.util';
@Pipe({ name: 'ucapI18n', pure: false })
export class I18nPipe implements PipeTransform, OnDestroy {
diff --git a/projects/i18n/src/lib/utils/object.util.ts b/projects/i18n/src/lib/utils/object.util.ts
deleted file mode 100644
index ac3b91b..0000000
--- a/projects/i18n/src/lib/utils/object.util.ts
+++ /dev/null
@@ -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;
- }
-}
diff --git a/projects/ui-authentication/ng-package.json b/projects/ui-authentication/ng-package.json
index a65bb52..29fe59a 100644
--- a/projects/ui-authentication/ng-package.json
+++ b/projects/ui-authentication/ng-package.json
@@ -4,6 +4,7 @@
"lib": {
"entryFile": "src/public-api.ts",
"umdModuleIds": {
+ "moment": "moment",
"@ucap/pi": "@ucap/pi",
"@ucap/ng-i18n": "@ucap/ng-i18n",
"@ucap/ng-ui": "@ucap/ng-ui"
diff --git a/projects/ui-authentication/package.json b/projects/ui-authentication/package.json
index 5b52fd3..eab2f29 100644
--- a/projects/ui-authentication/package.json
+++ b/projects/ui-authentication/package.json
@@ -1,6 +1,6 @@
{
"name": "@ucap/ng-ui-authentication",
- "version": "0.0.8",
+ "version": "0.0.13",
"publishConfig": {
"registry": "http://10.81.13.221:8081/nexus/repository/npm-ucap/"
},
diff --git a/projects/ui-authentication/src/lib/components/login.component.html b/projects/ui-authentication/src/lib/components/login.component.html
index b41c02d..af2b6b1 100644
--- a/projects/ui-authentication/src/lib/components/login.component.html
+++ b/projects/ui-authentication/src/lib/components/login.component.html
@@ -81,6 +81,7 @@
@@ -88,32 +89,63 @@
{{ 'login.errors.requireLoginId' | ucapI18n }}
{{ 'login.errors.requireLoginPw' | ucapI18n }}
+
+ {{ 'login.errors.failed' | ucapI18n }}
+
diff --git a/projects/ui-authentication/src/lib/components/login.component.ts b/projects/ui-authentication/src/lib/components/login.component.ts
index cd968c4..6466c22 100644
--- a/projects/ui-authentication/src/lib/components/login.component.ts
+++ b/projects/ui-authentication/src/lib/components/login.component.ts
@@ -1,3 +1,5 @@
+import moment from 'moment';
+
import {
Component,
OnInit,
@@ -16,6 +18,7 @@ import {
ValidatorFn
} from '@angular/forms';
import { Company } from '@ucap/api-external';
+import { LoginTry } from '@ucap/pi';
@Component({
selector: 'ucap-authentication-login',
@@ -41,6 +44,9 @@ export class LoginComponent implements OnInit {
@Input()
processing = false;
+ @Input()
+ loginTry: LoginTry;
+
@Output()
login = new EventEmitter<{
companyCode: string;
@@ -55,6 +61,9 @@ export class LoginComponent implements OnInit {
companyCodeFormControl = new FormControl('');
loginIdFormControl = new FormControl('');
loginPwFormControl = new FormControl('');
+ loginFailed = false;
+
+ moment = moment;
constructor(
private formBuilder: FormBuilder,
@@ -90,6 +99,7 @@ export class LoginComponent implements OnInit {
loginId: this.loginForm.get('loginIdFormControl').value,
loginPw: this.loginForm.get('loginPwFormControl').value,
notValid: () => {
+ this.loginFailed = true;
this.loginPwElementRef.nativeElement.focus();
}
});
diff --git a/projects/ui-organization/ng-package.json b/projects/ui-organization/ng-package.json
index 397ac92..02ce55b 100644
--- a/projects/ui-organization/ng-package.json
+++ b/projects/ui-organization/ng-package.json
@@ -4,6 +4,7 @@
"lib": {
"entryFile": "src/public-api.ts",
"umdModuleIds": {
+ "@ucap/core": "@ucap/core",
"@ucap/ng-ui": "@ucap/ng-ui"
}
}
diff --git a/projects/ui-organization/package.json b/projects/ui-organization/package.json
index 4bd97bf..d81d7f6 100644
--- a/projects/ui-organization/package.json
+++ b/projects/ui-organization/package.json
@@ -1,6 +1,6 @@
{
"name": "@ucap/ng-ui-organization",
- "version": "0.0.1",
+ "version": "0.0.2",
"publishConfig": {
"registry": "http://10.81.13.221:8081/nexus/repository/npm-ucap/"
},
diff --git a/projects/ui-organization/src/lib/organization-ui.module.ts b/projects/ui-organization/src/lib/organization-ui.module.ts
index 5e68ef6..99c4743 100644
--- a/projects/ui-organization/src/lib/organization-ui.module.ts
+++ b/projects/ui-organization/src/lib/organization-ui.module.ts
@@ -6,11 +6,15 @@ import { UiModule } from '@ucap/ng-ui';
import { ModuleConfig } from './config/module-config';
import { _MODULE_CONFIG } from './config/token';
+import { TranslatePipe } from './pipes/translate.pipe';
+
+import { TranslateService } from './services/translate.service';
+
const COMPONENTS = [];
const DIALOGS = [];
-const PIPES = [];
+const PIPES = [TranslatePipe];
const DIRECTIVES = [];
-const SERVICES = [];
+const SERVICES = [TranslateService];
@NgModule({
declarations: [],
diff --git a/projects/ui-organization/src/lib/pipes/translate.pipe.ts b/projects/ui-organization/src/lib/pipes/translate.pipe.ts
new file mode 100644
index 0000000..f61cfb3
--- /dev/null
+++ b/projects/ui-organization/src/lib/pipes/translate.pipe.ts
@@ -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();
+ }
+}
diff --git a/projects/ui-organization/src/lib/services/translate.service.ts b/projects/ui-organization/src/lib/services/translate.service.ts
new file mode 100644
index 0000000..1ea6234
--- /dev/null
+++ b/projects/ui-organization/src/lib/services/translate.service.ts
@@ -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 = new EventEmitter<
+ LangChangeEvent
+ >();
+ // tslint:disable-next-line: variable-name
+ private _changedDefaultLang: EventEmitter<
+ DefaultLangChangeEvent
+ > = new EventEmitter();
+ // 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 {
+ 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 });
+ }
+}
diff --git a/projects/ui-organization/src/public-api.ts b/projects/ui-organization/src/public-api.ts
index c826aac..b355138 100644
--- a/projects/ui-organization/src/public-api.ts
+++ b/projects/ui-organization/src/public-api.ts
@@ -4,4 +4,8 @@
export * from './lib/config/module-config';
+export * from './lib/pipes/translate.pipe';
+
+export * from './lib/services/translate.service';
+
export * from './lib/organization-ui.module';
diff --git a/projects/ui-organization/tslint.json b/projects/ui-organization/tslint.json
index ca80d1a..cbfb8a8 100644
--- a/projects/ui-organization/tslint.json
+++ b/projects/ui-organization/tslint.json
@@ -1,17 +1,7 @@
{
"extends": "../../tslint.json",
"rules": {
- "directive-selector": [
- true,
- "attribute",
- "ucapOrganization",
- "camelCase"
- ],
- "component-selector": [
- true,
- "element",
- "ucap-organization",
- "kebab-case"
- ]
+ "directive-selector": [true, "attribute", "ucapOrganization", "camelCase"],
+ "component-selector": [true, "element", "ucap-organization", "kebab-case"]
}
}