This commit is contained in:
snoop 2017-07-24 20:10:44 +09:00
commit 7e6846a2a8
11 changed files with 141 additions and 43 deletions

View File

@ -12,6 +12,9 @@ import Platform from '@overflow/commons/platform';
import AppContext from '@overflow/commons/context';
import * as AppContextLifecycleActions from '@overflow/commons/context/redux/action/lifecycle';
import WebSocketRPC from '@overflow/commons/websocket/WebSocketRPC';
import ReducerManager from '@overflow/commons/redux/ReducerManager';
import { store, sagaMiddleware, history } from './redux/store';
import appConfig, { Config } from './config';
@ -33,12 +36,14 @@ class Application {
private store: Store<any>;
private sagaMiddleware: SagaMiddleware<any>;
private history: History;
private reducerManager: ReducerManager;
public constructor() {
this.config = appConfig;
this.sagaMiddleware = sagaMiddleware;
this.store = store;
this.history = history;
this.reducerManager = new ReducerManager();
}
public static Run(): void {
@ -89,16 +94,15 @@ class Application {
}
private initRedux(): Promise<void> {
// state tree
// reducer
// middleware
// saga
const rpcClient = new Promise<void>(resolve => {
this.sagaMiddleware.run(sagas);
resolve();
const init = new Promise<void>(resolve => {
// state tree
// reducer
// middleware
// saga
});
return rpcClient;
return init;
}
private initSagaEffect(): Promise<void> {
@ -158,9 +162,7 @@ class Application {
}
private displayDebugApp(): void {
if (module.hot) {
// app
module.hot.accept('./views/App', async () => {
// const NextApp = require('./app').App;
const NextApp = (await import('./views/App')).default;
ReactDOM.render(
<AppContainer>

View File

@ -19,8 +19,6 @@ import {
composeWithDevTools,
} from 'redux-devtools-extension/logOnlyInProduction';
import reduxLogger from 'redux-logger';
import reducer from './reducer';
import State from './state';

View File

@ -3,7 +3,6 @@ import { Redirect, RouteComponentProps, RouteProps, Route, Switch } from 'react-
import { Container, Menu, Sidebar, Segment, Icon, Breadcrumb, Grid, Dropdown } from 'semantic-ui-react';
import { Header } from './Header';
import { Footer } from './Footer';
import { TitleBar } from './TitleBar';
import LeftMenu from './LeftMenu';
import Home from '../Home';
@ -38,7 +37,6 @@ export class AppLayout extends React.Component<Props, State> {
<LeftMenu />
<Segment vertical style={{ margin: '0 0 0 210px', padding: '0' }}>
<Header />
<TitleBar />
<Switch>
<Route exact={true} path={`${this.props.match.url}`} component={Home}/>
<Route exact={true} path={`${this.props.match.url}probes`} component={ProbeList}/>

View File

@ -13,6 +13,7 @@ import ProbeHistory from '../../views/monitoring/probe/History';
export interface Props extends RouteComponentProps<any> {
}
export interface State {
currUrl: string;
}
export class ProbeDetailLayout extends React.Component<Props, State> {
@ -20,6 +21,7 @@ export class ProbeDetailLayout extends React.Component<Props, State> {
constructor(props: Props, context: State) {
super(props, context);
this.state = {
currUrl: this.props.location.pathname,
};
}
@ -28,11 +30,11 @@ export class ProbeDetailLayout extends React.Component<Props, State> {
const sub = [
{
'name': 'Info',
'path': `${this.props.location.pathname}`,
'path': this.state.currUrl,
},
{
'name': 'History',
'path': `${this.props.location.pathname}/history`,
'path': this.state.currUrl + '/history',
},
];
return (
@ -40,7 +42,7 @@ export class ProbeDetailLayout extends React.Component<Props, State> {
<LeftMenu />
<Segment vertical style={{ margin: '0 0 0 210px', padding: '0' }}>
<Header />
<TitleBarContainer sub={sub}/>
<TitleBarContainer title='Probe Details' sub={sub}/>
<Switch>
<Route exact={true} path={`${this.props.match.url}/:id`} component={ProbeDetail} />
<Route exact={true} path={`${this.props.match.url}/:id/history`} component={ProbeHistory} />

View File

@ -4,6 +4,7 @@ import { Grid, Container, Breadcrumb, Header, Menu, Input, Segment } from 'seman
export interface StateProps {
sub: any;
title: any;
}
export interface DispatchProps {
@ -13,6 +14,7 @@ export interface DispatchProps {
export type Props = StateProps & DispatchProps;
export interface State {
selected: number;
}
export class TitleBar extends React.Component<Props, State> {
@ -20,12 +22,17 @@ export class TitleBar extends React.Component<Props, State> {
constructor(props: any, context: any) {
super(props, context);
this.state = {
selected: 0,
};
}
public handleMenu(menu:any): any {
console.log(menu.path);
this.props.onRedirect(menu.path);
public handleMenu(menu: any, index: number): any {
this.setState({
selected: index,
});
if (this.state.selected !== index) {
this.props.onRedirect(menu.path);
}
}
public renderSubMenus(): JSX.Element {
@ -35,15 +42,15 @@ export class TitleBar extends React.Component<Props, State> {
}
return subMenus.map((menu: any, index: number) => (
<Menu.Item key={index} name={menu.name} onClick={this.handleMenu.bind(this, menu)}/>
<Menu.Item key={index} name={menu.name} onClick={this.handleMenu.bind(this, menu, index)} active={this.state.selected === index} />
));
}
public render(): JSX.Element {
return (
<Menu fluid style={{ 'borderLeft': '0px', 'borderRight': '0px', 'boxShadow': 'none', 'borderRadius': '0' }}>
<Menu.Item name='TEMP' style={{ width: '250px' }}>
<Header as='h3'>TEMP
<Menu.Item style={{ width: '250px' }}>
<Header as='h3'>{this.props.title}
<Header.Subheader>
<Breadcrumb size='mini'>
<Breadcrumb.Section link>Home</Breadcrumb.Section>

View File

@ -10,6 +10,7 @@ import { push as routerPush } from 'react-router-redux';
export function mapStateToProps(state: any, ownProps: any): StateProps {
return {
sub: ownProps.sub,
title: ownProps.title,
};
}

View File

@ -4,6 +4,7 @@ import ProbeListContainer from '@overflow/probe/react/ProbeList';
import WebSocketRPC from '@overflow/commons/websocket/WebSocketRPC';
import AppContext from '@overflow/commons/context';
import inject from '@overflow/commons/context/decorator/inject';
import TitleBarContainer from '@overflow/app/views/layout/TitleBarContainer';
class ProbeList extends React.Component<RouteComponentProps<object>, object> {
@inject()
@ -17,7 +18,10 @@ class ProbeList extends React.Component<RouteComponentProps<object>, object> {
public render(): JSX.Element {
return (
<ProbeListContainer/>
<div>
<TitleBarContainer title='Probes' />
<ProbeListContainer />
</div>
);
}
}

View File

@ -0,0 +1,56 @@
import Action from './Action';
import * as Redux from 'redux';
interface ReducerItem<State> {
initialState: State;
reducer: Redux.Reducer<State>;
}
class ReducerManager {
private reducerMap: Map<string, ReducerItem<any>[]>;
public constructor() {
this.reducerMap = new Map();
}
public putReducer<State>(type: string, initialState: State, reducer: Redux.Reducer<State>): void {
let reducerItems: ReducerItem<any>[];
if (!this.reducerMap.has(type)) {
reducerItems = new Array();
this.reducerMap.set(type, reducerItems);
} else {
reducerItems = this.reducerMap.get(type);
}
let reducerItem: ReducerItem<State> = {
initialState: initialState,
reducer: reducer,
};
reducerItems.push(reducerItem);
}
public putReducers<State>(initialState: State, handlers: Redux.ReducersMapObject): void {
for(let type in handlers) {
if (handlers.hasOwnProperty(type)) {
this.putReducer(type, initialState, handlers[type]);
}
}
}
public reducer<State, A extends Action>(state: State, action: A): State {
const actionType = action.type;
if (this.reducerMap.has(actionType)) {
let reducerItems = this.reducerMap.get(actionType);
for (let reducerItem of reducerItems) {
let initialState = reducerItem.initialState;
let reducer = reducerItem.reducer;
state = reducer(state, action);
}
} else {
console.log(`Reducer for [${actionType}] is not loaded.`);
}
return state;
}
}
export default ReducerManager;

View File

@ -0,0 +1,19 @@
import Action from './Action';
import * as Redux from 'redux';
// export type Reducer<S> = <A extends Action>(state: S, action: A) => S;
// export interface ReducersMapObject {
// [key: string]: Reducer<any>;
// }
const createReducer = <State>(initialState: State, handlers: Redux.ReducersMapObject): Redux.Reducer<State> => {
return <A extends Action>(state: State = initialState, action: A): State => {
if (handlers[action.type]) {
return handlers[action.type](state, action);
}
return state;
};
};
export default createReducer;

View File

@ -1,4 +1,5 @@
import Action from '@overflow/commons/redux/Action';
import createReducer from '@overflow/commons/redux/createReducer';
import Member from '@overflow/member/api/model/Member';
import * as SigninActionTypes from '../action/signIn';
@ -6,24 +7,34 @@ import SigninState, { defaultState as signinDefaultState } from '../state/SignIn
export type reducer = (state: SigninState, action: Action<Member | Error>) => SigninState;
export const reducer: reducer = (state: SigninState = signinDefaultState, action: Action<Member | Error>): SigninState => {
switch (action.type) {
case SigninActionTypes.REQUEST_SUCCESS:
{
let member = (<Action<Member>>action).payload;
export const reducer: reducer = createReducer(signinDefaultState, {
[SigninActionTypes.REQUEST_SUCCESS]: (state: SigninState, action: Action<Member>): SigninState => {
return state;
},
[SigninActionTypes.REQUEST_FAILURE]: (state: SigninState, action: Action<Error>): SigninState => {
return state;
},
});
const aaa: SigninState = {
...state,
isAuthenticated: true,
};
return aaa;
}
case SigninActionTypes.REQUEST_FAILURE:
{
return state;
}
default:
return state;
}
};
// export const reducer: reducer = (state: SigninState = signinDefaultState, action: Action<Member | Error>): SigninState => {
// switch (action.type) {
// case SigninActionTypes.REQUEST_SUCCESS:
// {
// let member = (<Action<Member>>action).payload;
// const aaa: SigninState = {
// ...state,
// isAuthenticated: true,
// };
// return aaa;
// }
// case SigninActionTypes.REQUEST_FAILURE:
// {
// return state;
// }
// default:
// return state;
// }
// };