Skip to content

Commit

Permalink
SHIBUI-814 Integrated with rest endpoint for messages
Browse files Browse the repository at this point in the history
  • Loading branch information
rmathis committed Sep 5, 2018
1 parent 79fd205 commit 95256b6
Show file tree
Hide file tree
Showing 12 changed files with 266 additions and 9 deletions.
11 changes: 11 additions & 0 deletions backend/src/main/resources/i18n/messages_en-US.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
action.dashboard=Dashboard (en-US)
action.logout=Logout
action.add-new=Add New
action.clear=Clear

label.metadata-sources=Metadata Sources
label.metadata-source=Metadata Source
label.metadata-providers=Metadata Providers
label.metadata-provider=Metadata Provider
label.source-management=Source Management
label.search-files=Search Files
12 changes: 11 additions & 1 deletion backend/src/main/resources/i18n/messages_en.properties
Original file line number Diff line number Diff line change
@@ -1 +1,11 @@
a.sample.message=This is a sample message.
action.dashboard=Dashboard (en)
action.logout=Logout
action.add-new=Add New
action.clear=Clear

label.metadata-sources=Metadata Sources
label.metadata-source=Metadata Source
label.metadata-providers=Metadata Providers
label.metadata-provider=Metadata Provider
label.source-management=Source Management
label.search-files=Search Files
9 changes: 8 additions & 1 deletion ui/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import { Store } from '@ngrx/store';
import * as fromRoot from './core/reducer';
import { VersionInfo } from './core/model/version';
import { VersionInfoLoadRequestAction } from './core/action/version.action';
import { I18nService } from './core/service/i18n.service';
import { SetLanguage } from './core/action/message.action';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
Expand All @@ -21,12 +24,16 @@ export class AppComponent implements OnInit {

formatter = v => v && v.build ? `${v.build.version}-${v.git.commit.id}` : '';

constructor(private store: Store<fromRoot.State>) {
constructor(
private store: Store<fromRoot.State>,
private i18nService: I18nService
) {
this.version$ = this.store.select(fromRoot.getVersionInfo);
this.formatted$ = this.version$.pipe(map(this.formatter));
}

ngOnInit(): void {
this.store.dispatch(new VersionInfoLoadRequestAction());
this.store.dispatch(new SetLanguage(this.i18nService.getCurrentLanguage()));
}
}
4 changes: 3 additions & 1 deletion ui/src/app/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { NgModule, LOCALE_ID } from '@angular/core';
import { StoreModule } from '@ngrx/store';
import { EffectsModule } from '@ngrx/effects';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
Expand All @@ -24,6 +24,7 @@ import { SharedModule } from './shared/shared.module';
import { WizardModule } from './wizard/wizard.module';
import { FormModule } from './schema-form/schema-form.module';
import { environment } from '../environments/environment.prod';
import { getCurrentLanguage } from './shared/util';

@NgModule({
declarations: [
Expand Down Expand Up @@ -54,6 +55,7 @@ import { environment } from '../environments/environment.prod';
AppRoutingModule
],
providers: [
{ provide: LOCALE_ID, useValue: getCurrentLanguage() },
NavigatorService,
{ provide: RouterStateSerializer, useClass: CustomRouterStateSerializer },
{
Expand Down
39 changes: 39 additions & 0 deletions ui/src/app/core/action/message.action.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { Action } from '@ngrx/store';

export enum MessagesActionTypes {
MESSAGES_LOAD_REQUEST = '[Messages] Load REQUEST',
MESSAGES_LOAD_SUCCESS = '[Messages] Load SUCCESS',
MESSAGES_LOAD_ERROR = '[Messages] Load ERROR',

SET_LANGUAGE = '[Messages] Set Language'
}

export class MessagesLoadRequestAction implements Action {
readonly type = MessagesActionTypes.MESSAGES_LOAD_REQUEST;

constructor() { }
}

export class MessagesLoadSuccessAction implements Action {
readonly type = MessagesActionTypes.MESSAGES_LOAD_SUCCESS;

constructor(public payload: any) { }
}

export class MessagesLoadErrorAction implements Action {
readonly type = MessagesActionTypes.MESSAGES_LOAD_ERROR;

constructor(public payload: { message: string, type: string }) { }
}

export class SetLanguage implements Action {
readonly type = MessagesActionTypes.SET_LANGUAGE;

constructor(public payload: string) {}
}

export type Actions =
| MessagesLoadRequestAction
| MessagesLoadSuccessAction
| MessagesLoadErrorAction
| SetLanguage;
7 changes: 5 additions & 2 deletions ui/src/app/core/core.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import { UserEffects } from './effect/user.effect';
import { HttpClientModule } from '@angular/common/http';
import { ModalService } from './service/modal.service';
import { DifferentialService } from './service/differential.service';
import { I18nService } from './service/i18n.service';
import { MessageEffects } from './effect/message.effect';

export const COMPONENTS = [];

Expand All @@ -36,7 +38,8 @@ export class CoreModule {
FileService,
ModalService,
DifferentialService,
CanDeactivateGuard
CanDeactivateGuard,
I18nService
]
};
}
Expand All @@ -45,7 +48,7 @@ export class CoreModule {
@NgModule({
imports: [
StoreModule.forFeature('core', reducers),
EffectsModule.forFeature([UserEffects, VersionEffects]),
EffectsModule.forFeature([UserEffects, VersionEffects, MessageEffects]),
],
})
export class RootCoreModule { }
45 changes: 45 additions & 0 deletions ui/src/app/core/effect/message.effect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Injectable } from '@angular/core';
import { Effect, Actions, ofType } from '@ngrx/effects';

import { of } from 'rxjs';
import { map, catchError, switchMap, withLatestFrom } from 'rxjs/operators';

import {
MessagesActionTypes,
MessagesLoadErrorAction,
MessagesLoadRequestAction,
MessagesLoadSuccessAction,
SetLanguage
} from '../action/message.action';
import { I18nService } from '../service/i18n.service';
import * as fromCore from '../reducer';
import { Store } from '@ngrx/store';

@Injectable()
export class MessageEffects {

@Effect()
loadMessages$ = this.actions$.pipe(
ofType<MessagesLoadRequestAction>(MessagesActionTypes.MESSAGES_LOAD_REQUEST),
withLatestFrom(this.store.select(fromCore.getLanguage)),
switchMap(([action, lang]) => {
return this.i18nService.get(lang)
.pipe(
map(u => new MessagesLoadSuccessAction({ ...u })),
catchError(error => of(new MessagesLoadErrorAction(error)))
);
})
);
@Effect()
setLanguage$ = this.actions$.pipe(
ofType<SetLanguage>(MessagesActionTypes.SET_LANGUAGE),
map(action => action.payload),
map(language => new MessagesLoadRequestAction())
);

constructor(
private i18nService: I18nService,
private actions$: Actions,
private store: Store<fromCore.State>
) { }
}
4 changes: 1 addition & 3 deletions ui/src/app/core/effect/user.effect.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import { Injectable } from '@angular/core';
import { Effect, Actions, ofType } from '@ngrx/effects';
import { Location } from '@angular/common';

import { of } from 'rxjs';
import { map, tap, catchError, switchMap } from 'rxjs/operators';

import * as user from '../action/user.action';
import { User } from '../model/user';
import { UserService } from '../service/user.service';

@Injectable()
Expand Down Expand Up @@ -36,4 +34,4 @@ export class UserEffects {
private userService: UserService,
private actions$: Actions
) { }
}
}
11 changes: 10 additions & 1 deletion ui/src/app/core/reducer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ import {

import * as fromUser from './user.reducer';
import * as fromVersion from './version.reducer';
import * as fromMessages from './message.reducer';
import * as fromRoot from '../../app.reducer';

export interface CoreState {
user: fromUser.UserState;
version: fromVersion.VersionState;
messages: fromMessages.MessageState;
}

export interface State extends fromRoot.State {
Expand All @@ -23,12 +25,14 @@ export interface State extends fromRoot.State {

export const reducers = {
user: fromUser.reducer,
version: fromVersion.reducer
version: fromVersion.reducer,
messages: fromMessages.reducer
};

export const getCoreFeature = createFeatureSelector<CoreState>('core');
export const getUserStateFn = (state: CoreState) => state.user;
export const getVersionStateFn = (state: CoreState) => state.version;
export const getMessageStateFn = (state: CoreState) => state.messages;

export const getUserState = createSelector(getCoreFeature, getUserStateFn);
export const getUser = createSelector(getUserState, fromUser.getUser);
Expand All @@ -39,3 +43,8 @@ export const getVersionState = createSelector(getCoreFeature, (state: CoreState)
export const getVersionInfo = createSelector(getVersionState, fromVersion.getVersionInfo);
export const getVersionLoading = createSelector(getVersionState, fromVersion.getVersionIsLoading);
export const getVersionError = createSelector(getVersionState, fromVersion.getVersionError);

export const getMessageState = createSelector(getCoreFeature, getMessageStateFn);
export const getLanguage = createSelector(getMessageState, fromMessages.getLanguage);
export const getMessages = createSelector(getMessageState, fromMessages.getMessages);
export const getFetchingMessages = createSelector(getMessageState, fromMessages.isFetching);
60 changes: 60 additions & 0 deletions ui/src/app/core/reducer/message.reducer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import {
MessagesActionTypes,
Actions,

} from '../action/message.action';

export interface MessageState {
fetching: boolean;
messages: any;
error: any;
language: string;
}

export const initialState: MessageState = {
fetching: false,
messages: null,
error: null,
language: 'en'
};

export function reducer(state = initialState, action: Actions): MessageState {
switch (action.type) {
case MessagesActionTypes.MESSAGES_LOAD_REQUEST: {
return {
...state,
fetching: true
};
}
case MessagesActionTypes.MESSAGES_LOAD_SUCCESS: {
return {
...state,
fetching: false,
messages: action.payload
};
}
case MessagesActionTypes.MESSAGES_LOAD_ERROR: {
return {
...state,
fetching: false,
messages: null,
error: action.payload
};
}
case MessagesActionTypes.SET_LANGUAGE: {
return {
...state,
language: action.payload
};
}
default: {
return state;
}
}
}


export const getMessages = (state: MessageState) => state.messages;
export const getLanguage = (state: MessageState) => state.language;
export const getError = (state: MessageState) => state.error;
export const isFetching = (state: MessageState) => state.fetching;
31 changes: 31 additions & 0 deletions ui/src/app/core/service/i18n.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { HttpClient, HttpParams } from '@angular/common/http';
import { NavigatorService } from './navigator.service';
import { getCurrentLanguage } from '../../shared/util';

@Injectable()
export class I18nService {

readonly path = '/messages';
readonly base = '/api';

constructor(
private http: HttpClient,
private navigator: NavigatorService
) {}

get(language: string = null): Observable<any> {
let params: HttpParams = new HttpParams();
if (!!language) {
params = params.set('lang', language);
}
return this.http.get(`${ this.base }${this.path}`, {
params
});
}

getCurrentLanguage(): string {
return getCurrentLanguage(this.navigator.native);
}
}
42 changes: 42 additions & 0 deletions ui/src/app/shared/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,45 @@ export function array_move(arr, old_index, new_index): any[] {
arr.splice(new_index, 0, arr.splice(old_index, 1)[0]);
return arr;
}

export function getCurrentLanguage(nav: any = null): string {
nav = nav || navigator;
const getLocaleId = (lang: string) => lang.trim();
// supported regional languages
const supportedLanguages: string[] = ['en', 'es', 'en-US', 'es-ES'].map(lang => getLocaleId(lang));
// language code without regional details
const shortSupportedLanguages: string[] = supportedLanguages.map(lang => lang.substring(0, 2));

// look for an exact match to a regional translation
let preferredLanguage = getLocaleId(nav.language);
if (supportedLanguages.includes(preferredLanguage)) {
return preferredLanguage;
}

// for language only match, no regional details
let shortPreferredLanguage: string = preferredLanguage.substring(0, 2);
let index = shortSupportedLanguages.indexOf(shortPreferredLanguage);
if (index > -1) {
return supportedLanguages[index];
}

// not all browsers share full language list
if (nav.languages instanceof Array) {
// get list of all languages user understands, check for an exact regional match
const allPreferredLanugages: string[] = nav.languages.map(lang => getLocaleId(lang));
preferredLanguage = allPreferredLanugages.find(language => supportedLanguages.includes(language));
if (preferredLanguage) {
return preferredLanguage;
}

// from list of all languages user understand, check for language only match
const shortAllPreferredLanugages: string[] = allPreferredLanugages.map(language => language.substring(0, 2));
index = shortAllPreferredLanugages.findIndex(language => shortSupportedLanguages.includes(language));
if (index > -1) {
return supportedLanguages[index];
}
}

// if no match has been found return first (default) language
return supportedLanguages[0];
}

0 comments on commit 95256b6

Please sign in to comment.