Skip to content

Commit

Permalink
Merge pull request #757 from dahlbyk/initializer
Browse files Browse the repository at this point in the history
Extract Initializer
  • Loading branch information
ryanlanciaux committed Nov 16, 2017
2 parents 3466e7c + d2931e9 commit c1ce993
Show file tree
Hide file tree
Showing 11 changed files with 631 additions and 122 deletions.
1 change: 1 addition & 0 deletions .storybook/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const include = path.resolve(__dirname, '../');
// to "React Create App". This only has babel loader to load JavaScript.

module.exports = {
devtool: 'source-map',
entry: './stories/index.tsx',
output: {
filename: include + '/dist/examples/storybook.js'
Expand Down
15 changes: 15 additions & 0 deletions src/core/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import components from '../components';
import * as reducer from '../reducers/dataReducer';
import * as selectors from '../selectors/dataSelectors';
import * as actions from '../actions';
import initialState from './initialState';

const CorePlugin = {
components,
reducer,
selectors,
actions,
...initialState,
};

export default CorePlugin;
45 changes: 45 additions & 0 deletions src/core/initialState.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
const styleConfig = {
icons: {
TableHeadingCell: {
sortDescendingIcon: '▼',
sortAscendingIcon: '▲'
},
},
classNames: {
Cell: 'griddle-cell',
Filter: 'griddle-filter',
Loading: 'griddle-loadingResults',
NextButton: 'griddle-next-button',
NoResults: 'griddle-noResults',
PageDropdown: 'griddle-page-select',
Pagination: 'griddle-pagination',
PreviousButton: 'griddle-previous-button',
Row: 'griddle-row',
RowDefinition: 'griddle-row-definition',
Settings: 'griddle-settings',
SettingsToggle: 'griddle-settings-toggle',
Table: 'griddle-table',
TableBody: 'griddle-table-body',
TableHeading: 'griddle-table-heading',
TableHeadingCell: 'griddle-table-heading-cell',
TableHeadingCellAscending: 'griddle-heading-ascending',
TableHeadingCellDescending: 'griddle-heading-descending',
},
styles: {
}
};

export default {
styleConfig,

pageProperties: {
currentPage: 1,
pageSize: 10
},
enableSettings: true,
textProperties: {
next: 'Next',
previous: 'Previous',
settingsToggle: 'Settings'
},
};
123 changes: 9 additions & 114 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,60 +1,14 @@
import { createStore, combineReducers, bindActionCreators, applyMiddleware, compose } from 'redux';
import Immutable from 'immutable';
import { createProvider } from 'react-redux';
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import _ from 'lodash';

import * as dataReducers from './reducers/dataReducer';
import components from './components';
import settingsComponentObjects from './settingsComponentObjects';
import * as selectors from './selectors/dataSelectors';

import { buildGriddleReducer, buildGriddleComponents } from './utils/compositionUtils';
import { getColumnProperties } from './utils/columnUtils';
import { getRowProperties } from './utils/rowUtils';
import { setSortProperties } from './utils/sortUtils';
import corePlugin from './core';
import init from './utils/initializer';
import { StoreListener } from './utils/listenerUtils';
import * as actions from './actions';

const defaultEvents = {
...actions,
onFilter: actions.setFilter,
setSortProperties
};


const defaultStyleConfig = {
icons: {
TableHeadingCell: {
sortDescendingIcon: '▼',
sortAscendingIcon: '▲'
},
},
classNames: {
Cell: 'griddle-cell',
Filter: 'griddle-filter',
Loading: 'griddle-loadingResults',
NextButton: 'griddle-next-button',
NoResults: 'griddle-noResults',
PageDropdown: 'griddle-page-select',
Pagination: 'griddle-pagination',
PreviousButton: 'griddle-previous-button',
Row: 'griddle-row',
RowDefinition: 'griddle-row-definition',
Settings: 'griddle-settings',
SettingsToggle: 'griddle-settings-toggle',
Table: 'griddle-table',
TableBody: 'griddle-table-body',
TableHeading: 'griddle-table-heading',
TableHeadingCell: 'griddle-table-heading-cell',
TableHeadingCellAscending: 'griddle-heading-ascending',
TableHeadingCellDescending: 'griddle-heading-descending',
},
styles: {
}
};

class Griddle extends Component {
static childContextTypes = {
components: PropTypes.object.isRequired,
Expand All @@ -69,86 +23,23 @@ class Griddle extends Component {
super(props);

const {
plugins=[],
data,
children:rowPropertiesComponent,
events={},
sortProperties={},
styleConfig={},
pageProperties:importedPageProperties,
components:userComponents,
renderProperties:userRenderProperties={},
settingsComponentObjects:userSettingsComponentObjects,
core = corePlugin,
storeKey = Griddle.storeKey || 'store',
reduxMiddleware = [],
listeners = {},
...userInitialState
} = props;

const rowProperties = getRowProperties(rowPropertiesComponent);
const columnProperties = getColumnProperties(rowPropertiesComponent);

//Combine / compose the reducers to make a single, unified reducer
const reducers = buildGriddleReducer([dataReducers, ...plugins.map(p => p.reducer)]);

//Combine / Compose the components to make a single component for each component type
this.components = buildGriddleComponents([components, ...plugins.map(p => p.components), userComponents]);

this.settingsComponentObjects = Object.assign({}, settingsComponentObjects, ...plugins.map(p => p.settingsComponentObjects), userSettingsComponentObjects);

this.events = Object.assign({}, events, ...plugins.map(p => p.events));

this.selectors = plugins.reduce((combined, plugin) => ({ ...combined, ...plugin.selectors }), {...selectors});

const mergedStyleConfig = _.merge({}, defaultStyleConfig, ...plugins.map(p => p.styleConfig), styleConfig);

const pageProperties = Object.assign({}, {
currentPage: 1,
pageSize: 10
},
importedPageProperties,
);

//TODO: This should also look at the default and plugin initial state objects
const renderProperties = Object.assign({
rowProperties,
columnProperties
}, ...plugins.map(p => p.renderProperties), userRenderProperties);

// TODO: Make this its own method
const initialState = _.merge(
{
enableSettings: true,
textProperties: {
next: 'Next',
previous: 'Previous',
settingsToggle: 'Settings'
},
},
...plugins.map(p => p.initialState),
userInitialState,
{
data,
pageProperties,
renderProperties,
sortProperties,
styleConfig: mergedStyleConfig,
}
);
const { initialState, reducers, reduxMiddleware } = init.call(this, core);

const composeEnhancers = (typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) || compose
this.store = createStore(
reducers,
initialState,
composeEnhancers(
applyMiddleware(..._.compact(_.flatten(plugins.map(p => p.reduxMiddleware))), ...reduxMiddleware)
applyMiddleware(...reduxMiddleware)
)
);

this.provider = createProvider(storeKey);

const sanitizedListeners = _.pickBy(listeners, (value, key) => typeof value === "function");
this.listeners = plugins.reduce((combined, plugin) => ({...combined, ..._.pickBy(plugin.listeners, (value, key) => typeof value === "function")}), {...sanitizedListeners});
this.storeListener = new StoreListener(this.store);
_.forIn(this.listeners, (listener, name) => {
this.storeListener.addListener(listener, name, {events: this.events, selectors: this.selectors});
Expand Down Expand Up @@ -188,6 +79,10 @@ class Griddle extends Component {
}

render() {
if (!this.components.Layout) {
return null;
}

return (
<this.provider store={this.store}>
<this.components.Layout />
Expand Down
7 changes: 5 additions & 2 deletions src/module.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,9 @@ interface GriddleExtensibility {

interface GriddleInitialState {
enableSettings?: boolean;
pageProperties?: GriddlePageProperties;
sortMethod?: (data: any[], column: string, sortAscending?: boolean) => number;
sortProperties?: GriddleSortKey[];
textProperties?: {
next?: string,
previous?: string,
Expand All @@ -399,10 +401,9 @@ export interface GriddlePlugin extends GriddleExtensibility {
}

export interface GriddleProps<T> extends GriddlePlugin, GriddleInitialState {
core?: GriddlePlugin;
plugins?: GriddlePlugin[];
data?: T[];
sortProperties?: GriddleSortKey[];
pageProperties?: GriddlePageProperties;
storeKey?: string;
}

Expand Down Expand Up @@ -441,6 +442,8 @@ export namespace utils {
}

export namespace plugins {
var CorePlugin : GriddlePlugin;

var LegacyStylePlugin : GriddlePlugin;

var LocalPlugin : GriddlePlugin;
Expand Down
2 changes: 2 additions & 0 deletions src/module.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ import * as selectors from './selectors/dataSelectors';
import settingsComponentObjects from './settingsComponentObjects';
import utils from './utils';

import CorePlugin from './core';
import LegacyStylePlugin from './plugins/legacyStyle';
import LocalPlugin from './plugins/local';
import PositionPlugin from './plugins/position';

const plugins = {
CorePlugin,
LegacyStylePlugin,
LocalPlugin,
PositionPlugin,
Expand Down
20 changes: 18 additions & 2 deletions src/utils/__tests__/compositionUtilsTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {
removeHooksFromObject,
isKeyGriddleHook,
buildGriddleReducer,
buildGriddleReducerObject,
getAfterHooksFromObject,
getBeforeHooksFromObject,
removeKeyNamePartFromObject,
Expand Down Expand Up @@ -326,7 +325,7 @@ test('builds griddle reducer', test => {
}
}

const griddleReducer = buildGriddleReducerObject([reducer1, reducer2, reducer3]);
const griddleReducer = buildGriddleReducer([reducer1, reducer2, reducer3]);

test.deepEqual(Object.keys(griddleReducer), ['REDUCE_THING', 'REDUCE_OTHER']);
test.deepEqual(griddleReducer.REDUCE_THING({ number: 5}), { number: -45 });
Expand Down Expand Up @@ -357,6 +356,7 @@ test('builds griddle reducer with BEFORE_REDUCE and AFTER_REDUCE', (t) => {
const griddleReducer = buildGriddleReducer([reducer1, reducer2]);
const output = griddleReducer({number: 5}, { type: 'REDUCE_THING'});

t.deepEqual(Object.keys(griddleReducer), ['AFTER_REDUCE', 'REDUCE_THING', 'BEFORE_REDUCE']);
t.deepEqual(output, { number: 55 });
});

Expand All @@ -376,9 +376,25 @@ test('builds griddle reducer without BEFORE / AFTER if they dont exist', (t) =>
const griddleReducer = buildGriddleReducer([reducer1, reducer2]);
const output = griddleReducer({number: 5}, { type: 'REDUCE_THING'});

t.deepEqual(Object.keys(griddleReducer), ['REDUCE_THING']);
t.deepEqual(output, { number: 15 });
});

test('builds griddle reducer that calls GRIDDLE_INITIALIZED for missing action type, if it exists', (assert) => {
const initReducer = { GRIDDLE_INITIALIZED: () => ({ init: true }) };
const griddleReducer = buildGriddleReducer([initReducer]);
const output = griddleReducer({}, { type: 'MISSING' });

assert.deepEqual(output, { init: true });
});

test('builds griddle reducer that does noop for missing action type, if GRIDDLE_INITIALIZED is also missing', (assert) => {
const griddleReducer = buildGriddleReducer([]);
const output = griddleReducer({}, { type: 'MISSING' });

assert.deepEqual(output, {});
});

test('combineAndEnhanceComponents', test => {
const initial = { one: (someNumber) => (someNumber + 5)}
const enhancing = { oneEnhancer: originalMethod => (someNumber) => originalMethod(someNumber * 5)};
Expand Down
Loading

0 comments on commit c1ce993

Please sign in to comment.