From 73db68b771e123d970516192624714bc983e8290 Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Sat, 23 Sep 2017 14:48:57 -0500 Subject: [PATCH 01/27] Enable Storybook source-map --- .storybook/webpack.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/.storybook/webpack.config.js b/.storybook/webpack.config.js index 0296706f..9fff095a 100644 --- a/.storybook/webpack.config.js +++ b/.storybook/webpack.config.js @@ -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' From 82bde75eb3d1ddb64c526ff6b59ea150f4ba97a6 Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Sat, 23 Sep 2017 15:32:19 -0500 Subject: [PATCH 02/27] Extract initializer util from Griddle constructor --- src/index.js | 71 +++++------------------------ src/utils/initializer.js | 97 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+), 60 deletions(-) create mode 100644 src/utils/initializer.js diff --git a/src/index.js b/src/index.js index a898eead..3e7b8d79 100644 --- a/src/index.js +++ b/src/index.js @@ -1,5 +1,4 @@ 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'; @@ -10,9 +9,7 @@ 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 init from './utils/initializer'; import { setSortProperties } from './utils/sortUtils'; import { StoreListener } from './utils/listenerUtils'; import * as actions from './actions'; @@ -69,55 +66,20 @@ class Griddle extends Component { super(props); const { - plugins=[], - data, - children:rowPropertiesComponent, - events={}, - sortProperties={}, - styleConfig={}, - pageProperties:importedPageProperties, - components:userComponents, - renderProperties:userRenderProperties={}, - settingsComponentObjects:userSettingsComponentObjects, 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({}, { + const { initialState, reducers, reduxMiddleware } = init.call(this, { + reducers: dataReducers, + components, + settingsComponentObjects, + selectors, + styleConfig: defaultStyleConfig, + pageProperties: { 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( - { + initialState: { enableSettings: true, textProperties: { next: 'Next', @@ -125,30 +87,19 @@ class Griddle extends Component { settingsToggle: 'Settings' }, }, - ...plugins.map(p => p.initialState), - userInitialState, - { - data, - pageProperties, - renderProperties, - sortProperties, - styleConfig: mergedStyleConfig, - } - ); + }); const composeEnhancers = 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}); diff --git a/src/utils/initializer.js b/src/utils/initializer.js new file mode 100644 index 00000000..6a71ed2d --- /dev/null +++ b/src/utils/initializer.js @@ -0,0 +1,97 @@ +import _ from 'lodash'; +import { buildGriddleReducer, buildGriddleComponents } from './compositionUtils'; +import { getColumnProperties } from './columnUtils'; +import { getRowProperties } from './rowUtils'; + +module.exports = function initializer(defaults) { + if (!this) throw new Error('this missing!'); + + const { + reducers: dataReducers, + components, + settingsComponentObjects, + selectors, + styleConfig: defaultStyleConfig, + pageProperties: defaultPageProperties, + initialState: defaultInitialState, + } = defaults; + + const { + plugins = [], + data, + children: rowPropertiesComponent, + events: userEvents = {}, + sortProperties = {}, + styleConfig: userStyleConfig = {}, + pageProperties: userPageProperties, + components: userComponents, + renderProperties: userRenderProperties = {}, + settingsComponentObjects: userSettingsComponentObjects, + reduxMiddleware = [], + listeners = {}, + ...userInitialState + } = this.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({}, userEvents, ...plugins.map(p => p.events)); + + this.selectors = plugins.reduce( + (combined, plugin) => ({ ...combined, ...plugin.selectors }), + { ...selectors }); + + const styleConfig = _.merge( + { ...defaultStyleConfig }, + ...plugins.map(p => p.styleConfig), + userStyleConfig); + + const pageProperties = Object.assign({}, defaultPageProperties, userPageProperties); + + // 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( + defaultInitialState, + ...plugins.map(p => p.initialState), + userInitialState, + { + data, + pageProperties, + renderProperties, + sortProperties, + styleConfig, + } + ); + + const sanitizedListeners = _.pickBy(listeners, value => typeof value === 'function'); + this.listeners = plugins.reduce((combined, plugin) => ({ ...combined, ..._.pickBy(plugin.listeners, value => typeof value === 'function') }), sanitizedListeners); + + return { + initialState, + reducers, + reduxMiddleware: [ + ..._.compact(_.flatten(plugins.map(p => p.reduxMiddleware))), + ...reduxMiddleware + ], + }; +}; From 0d83e0cecc9667dc45cddd7728380aab16db1910 Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Sat, 23 Sep 2017 22:49:18 -0500 Subject: [PATCH 03/27] Add basic initializer tests --- src/utils/__tests__/initilizerTests.js | 71 ++++++++++++++++++++++++++ src/utils/initializer.js | 2 +- 2 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 src/utils/__tests__/initilizerTests.js diff --git a/src/utils/__tests__/initilizerTests.js b/src/utils/__tests__/initilizerTests.js new file mode 100644 index 00000000..81b38292 --- /dev/null +++ b/src/utils/__tests__/initilizerTests.js @@ -0,0 +1,71 @@ +import test from 'ava'; + +import init from '../initializer'; + +test('init succeeds given empty defaults and props', (assert) => { + const ctx = { props: {} }; + const defaults = {}; + + const res = init.call(ctx, defaults); + assert.truthy(res); + + assert.deepEqual(res.initialState, { + data: [], + pageProperties: {}, + renderProperties: { + rowProperties: null, + columnProperties: {}, + }, + sortProperties: {}, + styleConfig: {}, + }); + + assert.is(typeof res.reducers, 'function'); + + assert.deepEqual(res.reduxMiddleware, []); + + assert.deepEqual(ctx.components, {}); + assert.deepEqual(ctx.settingsComponentObjects, {}); + assert.deepEqual(ctx.events, {}); + assert.deepEqual(ctx.selectors, {}); + assert.deepEqual(ctx.listeners, {}); +}); + +test('init returns defaults given minimum props', (assert) => { + const ctx = { props: { data: [] } }; + const defaults = { + reducers: { REDUCE: () => ({ reduced: true }) }, + components: { Layout: () => null }, + settingsComponentObjects: { mySettings: { order: 10 } }, + selectors: { aSelector: () => null }, + styleConfig: { classNames: {} }, + pageProperties: { pageSize: 100 }, + initialState: { init: true }, + }; + + const res = init.call(ctx, defaults); + assert.truthy(res); + + assert.deepEqual(res.initialState, { + init: true, + data: ctx.props.data, + pageProperties: defaults.pageProperties, + renderProperties: { + rowProperties: null, + columnProperties: {}, + }, + sortProperties: {}, + styleConfig: defaults.styleConfig, + }); + + assert.is(typeof res.reducers, 'function'); + assert.deepEqual(res.reducers({}, { type: 'REDUCE' }), { reduced: true }); + + assert.deepEqual(res.reduxMiddleware, []); + + assert.deepEqual(ctx.components, defaults.components); + assert.deepEqual(ctx.settingsComponentObjects, defaults.settingsComponentObjects); + assert.deepEqual(ctx.events, {}); + assert.deepEqual(ctx.selectors, defaults.selectors); + assert.deepEqual(ctx.listeners, {}); +}); diff --git a/src/utils/initializer.js b/src/utils/initializer.js index 6a71ed2d..49cd3f2e 100644 --- a/src/utils/initializer.js +++ b/src/utils/initializer.js @@ -18,7 +18,7 @@ module.exports = function initializer(defaults) { const { plugins = [], - data, + data = [], children: rowPropertiesComponent, events: userEvents = {}, sortProperties = {}, From 75bcb8d231e275c6a72a8501a69aa536962d8e5f Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Sat, 23 Sep 2017 22:51:35 -0500 Subject: [PATCH 04/27] Fix reducer composition for tests --- src/utils/__tests__/compositionUtilsTest.js | 15 +++++++++++++++ src/utils/__tests__/initilizerTests.js | 1 + src/utils/compositionUtils.js | 2 +- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/utils/__tests__/compositionUtilsTest.js b/src/utils/__tests__/compositionUtilsTest.js index c163212d..ae4ce8f1 100644 --- a/src/utils/__tests__/compositionUtilsTest.js +++ b/src/utils/__tests__/compositionUtilsTest.js @@ -379,6 +379,21 @@ test('builds griddle reducer without BEFORE / AFTER if they dont exist', (t) => 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)}; diff --git a/src/utils/__tests__/initilizerTests.js b/src/utils/__tests__/initilizerTests.js index 81b38292..896bc157 100644 --- a/src/utils/__tests__/initilizerTests.js +++ b/src/utils/__tests__/initilizerTests.js @@ -21,6 +21,7 @@ test('init succeeds given empty defaults and props', (assert) => { }); assert.is(typeof res.reducers, 'function'); + assert.deepEqual(res.reducers({}, { type: 'REDUCE' }), {}); assert.deepEqual(res.reduxMiddleware, []); diff --git a/src/utils/compositionUtils.js b/src/utils/compositionUtils.js index 78b68177..91132b43 100644 --- a/src/utils/compositionUtils.js +++ b/src/utils/compositionUtils.js @@ -227,7 +227,7 @@ export function callReducerWithBeforeAfterPipe(reducerObject, state, action) { const call = (action.type && reducerObject[action.type] && reducerObject[action.type] - ) || reducerObject.GRIDDLE_INITIALIZED; + ) || reducerObject.GRIDDLE_INITIALIZED || noop; const partialCall = (partialAction => partialState => call(partialState, partialAction))(action); From a2a53eb86634bfb7bc9ff7a76e2d17c3d2c133d9 Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Sat, 23 Sep 2017 22:57:20 -0500 Subject: [PATCH 05/27] Attach individual reducers to Griddle reducer to help debugging/testing --- src/utils/__tests__/compositionUtilsTest.js | 5 +++-- src/utils/__tests__/initilizerTests.js | 1 + src/utils/compositionUtils.js | 7 +++++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/utils/__tests__/compositionUtilsTest.js b/src/utils/__tests__/compositionUtilsTest.js index ae4ce8f1..40b777e2 100644 --- a/src/utils/__tests__/compositionUtilsTest.js +++ b/src/utils/__tests__/compositionUtilsTest.js @@ -11,7 +11,6 @@ import { removeHooksFromObject, isKeyGriddleHook, buildGriddleReducer, - buildGriddleReducerObject, getAfterHooksFromObject, getBeforeHooksFromObject, removeKeyNamePartFromObject, @@ -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 }); @@ -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 }); }); @@ -376,6 +376,7 @@ 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 }); }); diff --git a/src/utils/__tests__/initilizerTests.js b/src/utils/__tests__/initilizerTests.js index 896bc157..de42ce09 100644 --- a/src/utils/__tests__/initilizerTests.js +++ b/src/utils/__tests__/initilizerTests.js @@ -60,6 +60,7 @@ test('init returns defaults given minimum props', (assert) => { }); assert.is(typeof res.reducers, 'function'); + assert.deepEqual(Object.keys(res.reducers), Object.keys(defaults.reducers)); assert.deepEqual(res.reducers({}, { type: 'REDUCE' }), { reduced: true }); assert.deepEqual(res.reduxMiddleware, []); diff --git a/src/utils/compositionUtils.js b/src/utils/compositionUtils.js index 91132b43..ed94f9a2 100644 --- a/src/utils/compositionUtils.js +++ b/src/utils/compositionUtils.js @@ -171,9 +171,10 @@ export function composeReducerObjects(reducerObjects) { /** Builds a new reducer that composes hooks and extends standard reducers between reducerObjects * @param {Object } reducers - An array of reducerObjects + * Note: this used to be exported, but the same properties are available from buildGriddleReducer. * TODO: This method should be broken down a bit -- it's doing too much currently */ -export function buildGriddleReducerObject(reducerObjects) { +function buildGriddleReducerObject(reducerObjects) { let reducerMethodsWithoutHooks = []; let beforeHooks = []; let afterHooks = []; @@ -241,7 +242,9 @@ export function callReducerWithBeforeAfterPipe(reducerObject, state, action) { */ export function buildGriddleReducer(reducerObjects) { const reducerObject = buildGriddleReducerObject(reducerObjects); - return (state, action) => callReducerWithBeforeAfterPipe(reducerObject, state, action); + const reducer = (state, action) => callReducerWithBeforeAfterPipe(reducerObject, state, action); + Object.assign(reducer, reducerObject); + return reducer; } /** Gets all reducers by a specific wordEnding From df08a82dea404972e341f42d45ff35c5b38796c0 Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Sun, 24 Sep 2017 17:38:29 -0500 Subject: [PATCH 06/27] Test initialState.data --- src/utils/__tests__/initilizerTests.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/utils/__tests__/initilizerTests.js b/src/utils/__tests__/initilizerTests.js index de42ce09..988875b8 100644 --- a/src/utils/__tests__/initilizerTests.js +++ b/src/utils/__tests__/initilizerTests.js @@ -71,3 +71,17 @@ test('init returns defaults given minimum props', (assert) => { assert.deepEqual(ctx.selectors, defaults.selectors); assert.deepEqual(ctx.listeners, {}); }); + +test('init returns expected initialState.data given props.data', (assert) => { + const ctx = { + props: { + data: [{ foo: 'bar' }], + }, + }; + const defaults = {}; + + const res = init.call(ctx, defaults); + assert.truthy(res); + + assert.deepEqual(res.initialState.data, ctx.props.data); +}); From e48f427bcff257c4f513005cb0682ab7c616e760 Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Sun, 24 Sep 2017 17:38:39 -0500 Subject: [PATCH 07/27] Test initialState.renderProperties --- src/utils/__tests__/initilizerTests.js | 31 ++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/utils/__tests__/initilizerTests.js b/src/utils/__tests__/initilizerTests.js index 988875b8..d589342a 100644 --- a/src/utils/__tests__/initilizerTests.js +++ b/src/utils/__tests__/initilizerTests.js @@ -2,6 +2,9 @@ import test from 'ava'; import init from '../initializer'; +import { getColumnProperties } from '../columnUtils'; +import { getRowProperties } from '../rowUtils'; + test('init succeeds given empty defaults and props', (assert) => { const ctx = { props: {} }; const defaults = {}; @@ -85,3 +88,31 @@ test('init returns expected initialState.data given props.data', (assert) => { assert.deepEqual(res.initialState.data, ctx.props.data); }); + +test('init returns expected initialState.renderProperties given props (children, plugins, user)', (assert) => { + const ctx = { + props: { + children: { + props: { + children: [{ props: { id: 'foo', order: 1 } }], + } + }, + plugins: [ + { renderProperties: { plugin: 0, user: false } }, + { renderProperties: { plugin: 1 } }, + ], + renderProperties: { user: true }, + }, + }; + const defaults = {}; + + const res = init.call(ctx, defaults); + assert.truthy(res); + + assert.deepEqual(res.initialState.renderProperties, { + rowProperties: getRowProperties(ctx.props.children), + columnProperties: getColumnProperties(ctx.props.children), + plugin: 1, + user: true, + }); +}); From b8e45b9b4437b63f458e8914efdefedd8601cbbc Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Sun, 24 Sep 2017 17:41:34 -0500 Subject: [PATCH 08/27] Test initialState.pageProperties --- src/utils/__tests__/initilizerTests.js | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/utils/__tests__/initilizerTests.js b/src/utils/__tests__/initilizerTests.js index d589342a..340b18d6 100644 --- a/src/utils/__tests__/initilizerTests.js +++ b/src/utils/__tests__/initilizerTests.js @@ -89,6 +89,28 @@ test('init returns expected initialState.data given props.data', (assert) => { assert.deepEqual(res.initialState.data, ctx.props.data); }); +test('init returns expected initialState.pageProperties given props (user)', (assert) => { + const ctx = { + props: { + pageProperties: { user: true }, + }, + }; + const defaults = { + pageProperties: { + defaults: true, + user: false, + }, + }; + + const res = init.call(ctx, defaults); + assert.truthy(res); + + assert.deepEqual(res.initialState.pageProperties, { + defaults: true, + user: true, + }); +}); + test('init returns expected initialState.renderProperties given props (children, plugins, user)', (assert) => { const ctx = { props: { From 9704acff8a12aa37b00ef0b89db8239154799412 Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Sun, 24 Sep 2017 17:44:29 -0500 Subject: [PATCH 09/27] Test initialState.sortProperties --- src/utils/__tests__/initilizerTests.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/utils/__tests__/initilizerTests.js b/src/utils/__tests__/initilizerTests.js index 340b18d6..4e451cab 100644 --- a/src/utils/__tests__/initilizerTests.js +++ b/src/utils/__tests__/initilizerTests.js @@ -138,3 +138,19 @@ test('init returns expected initialState.renderProperties given props (children, user: true, }); }); + +test('init returns expected initialState.sortProperties given props (user)', (assert) => { + const ctx = { + props: { + sortProperties: { user: true }, + }, + }; + const defaults = {}; + + const res = init.call(ctx, defaults); + assert.truthy(res); + + assert.deepEqual(res.initialState.sortProperties, { + user: true, + }); +}); From 4c15ac7c6f56cc7d31477d772c2a9f5eb7fa7ae7 Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Sun, 24 Sep 2017 17:57:28 -0500 Subject: [PATCH 10/27] Test initialState.styleConfig --- src/utils/__tests__/initilizerTests.js | 32 ++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/utils/__tests__/initilizerTests.js b/src/utils/__tests__/initilizerTests.js index 4e451cab..f30c0107 100644 --- a/src/utils/__tests__/initilizerTests.js +++ b/src/utils/__tests__/initilizerTests.js @@ -154,3 +154,35 @@ test('init returns expected initialState.sortProperties given props (user)', (as user: true, }); }); + +test('init returns merged initialState.styleConfig given props (plugins, user)', (assert) => { + const ctx = { + props: { + plugins: [ + { styleConfig: { styles: { plugin: 0, user: false } } }, + { styleConfig: { styles: { plugin: 1, defaults: false } } }, + ], + styleConfig: { + styles: { user: true }, + }, + }, + }; + const defaults = { + styleConfig: { + classNames: { defaults: true }, + styles: { defaults: true, plugin: false, user: false }, + }, + }; + + const res = init.call(ctx, defaults); + assert.truthy(res); + + assert.deepEqual(res.initialState.styleConfig, { + classNames: { defaults: true }, + styles: { + defaults: false, + plugin: 1, + user: true, + }, + }); +}); From c4c6728b3efed0728ffa400cecbbe022877ea1fd Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Sun, 24 Sep 2017 18:11:19 -0500 Subject: [PATCH 11/27] Test extra initialState props --- src/utils/__tests__/initilizerTests.js | 59 +++++++++++++++++++------- 1 file changed, 44 insertions(+), 15 deletions(-) diff --git a/src/utils/__tests__/initilizerTests.js b/src/utils/__tests__/initilizerTests.js index f30c0107..d5793940 100644 --- a/src/utils/__tests__/initilizerTests.js +++ b/src/utils/__tests__/initilizerTests.js @@ -5,6 +5,17 @@ import init from '../initializer'; import { getColumnProperties } from '../columnUtils'; import { getRowProperties } from '../rowUtils'; +const expectedDefaultInitialState = { + data: [], + pageProperties: {}, + renderProperties: { + rowProperties: null, + columnProperties: {}, + }, + sortProperties: {}, + styleConfig: {}, +}; + test('init succeeds given empty defaults and props', (assert) => { const ctx = { props: {} }; const defaults = {}; @@ -12,16 +23,7 @@ test('init succeeds given empty defaults and props', (assert) => { const res = init.call(ctx, defaults); assert.truthy(res); - assert.deepEqual(res.initialState, { - data: [], - pageProperties: {}, - renderProperties: { - rowProperties: null, - columnProperties: {}, - }, - sortProperties: {}, - styleConfig: {}, - }); + assert.deepEqual(res.initialState, expectedDefaultInitialState); assert.is(typeof res.reducers, 'function'); assert.deepEqual(res.reducers({}, { type: 'REDUCE' }), {}); @@ -51,14 +53,11 @@ test('init returns defaults given minimum props', (assert) => { assert.truthy(res); assert.deepEqual(res.initialState, { + ...expectedDefaultInitialState, + init: true, data: ctx.props.data, pageProperties: defaults.pageProperties, - renderProperties: { - rowProperties: null, - columnProperties: {}, - }, - sortProperties: {}, styleConfig: defaults.styleConfig, }); @@ -186,3 +185,33 @@ test('init returns merged initialState.styleConfig given props (plugins, user)', }, }); }); + +test('init returns expected extra initialState given props (plugins, user)', (assert) => { + const ctx = { + props: { + plugins: [ + { initialState: { plugin: 0, user: false } }, + { initialState: { plugin: 1 } }, + ], + user: true, + }, + }; + const defaults = { + initialState: { + defaults: true, + user: false, + plugin: false, + } + }; + + const res = init.call(ctx, defaults); + assert.truthy(res); + + assert.deepEqual(res.initialState, { + ...expectedDefaultInitialState, + + defaults: true, + user: true, + plugin: 1, + }); +}); From 24f27ccc3b424bd0261dde61e56c3f0d028776f2 Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Sun, 24 Sep 2017 18:17:56 -0500 Subject: [PATCH 12/27] Avoid initialState key in init defaults --- src/index.js | 13 ++++++------- src/utils/__tests__/initilizerTests.js | 10 ++++------ src/utils/initializer.js | 2 +- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/index.js b/src/index.js index 3e7b8d79..5bcfba63 100644 --- a/src/index.js +++ b/src/index.js @@ -79,13 +79,12 @@ class Griddle extends Component { currentPage: 1, pageSize: 10 }, - initialState: { - enableSettings: true, - textProperties: { - next: 'Next', - previous: 'Previous', - settingsToggle: 'Settings' - }, + + enableSettings: true, + textProperties: { + next: 'Next', + previous: 'Previous', + settingsToggle: 'Settings' }, }); diff --git a/src/utils/__tests__/initilizerTests.js b/src/utils/__tests__/initilizerTests.js index d5793940..fa6223b0 100644 --- a/src/utils/__tests__/initilizerTests.js +++ b/src/utils/__tests__/initilizerTests.js @@ -46,7 +46,7 @@ test('init returns defaults given minimum props', (assert) => { selectors: { aSelector: () => null }, styleConfig: { classNames: {} }, pageProperties: { pageSize: 100 }, - initialState: { init: true }, + init: true, }; const res = init.call(ctx, defaults); @@ -197,11 +197,9 @@ test('init returns expected extra initialState given props (plugins, user)', (as }, }; const defaults = { - initialState: { - defaults: true, - user: false, - plugin: false, - } + defaults: true, + user: false, + plugin: false, }; const res = init.call(ctx, defaults); diff --git a/src/utils/initializer.js b/src/utils/initializer.js index 49cd3f2e..6a51c161 100644 --- a/src/utils/initializer.js +++ b/src/utils/initializer.js @@ -13,7 +13,7 @@ module.exports = function initializer(defaults) { selectors, styleConfig: defaultStyleConfig, pageProperties: defaultPageProperties, - initialState: defaultInitialState, + ...defaultInitialState } = defaults; const { From 5acfc42d9d3d2982b1d5eb3420449b01a431600f Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Sun, 24 Sep 2017 18:19:42 -0500 Subject: [PATCH 13/27] Avoid special treatment for pageProperties --- src/index.js | 2 +- src/module.d.ts | 2 +- src/utils/__tests__/initilizerTests.js | 1 - src/utils/initializer.js | 4 ---- 4 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/index.js b/src/index.js index 5bcfba63..c99435df 100644 --- a/src/index.js +++ b/src/index.js @@ -75,11 +75,11 @@ class Griddle extends Component { settingsComponentObjects, selectors, styleConfig: defaultStyleConfig, + pageProperties: { currentPage: 1, pageSize: 10 }, - enableSettings: true, textProperties: { next: 'Next', diff --git a/src/module.d.ts b/src/module.d.ts index b25f4af4..84bfd841 100644 --- a/src/module.d.ts +++ b/src/module.d.ts @@ -383,6 +383,7 @@ interface GriddleExtensibility { interface GriddleInitialState { enableSettings?: boolean; + pageProperties?: GriddlePageProperties; sortMethod?: (data: any[], column: string, sortAscending?: boolean) => number; textProperties?: { next?: string, @@ -402,7 +403,6 @@ export interface GriddleProps extends GriddlePlugin, GriddleInitialState { plugins?: GriddlePlugin[]; data?: T[]; sortProperties?: GriddleSortKey[]; - pageProperties?: GriddlePageProperties; storeKey?: string; } diff --git a/src/utils/__tests__/initilizerTests.js b/src/utils/__tests__/initilizerTests.js index fa6223b0..f54318f4 100644 --- a/src/utils/__tests__/initilizerTests.js +++ b/src/utils/__tests__/initilizerTests.js @@ -7,7 +7,6 @@ import { getRowProperties } from '../rowUtils'; const expectedDefaultInitialState = { data: [], - pageProperties: {}, renderProperties: { rowProperties: null, columnProperties: {}, diff --git a/src/utils/initializer.js b/src/utils/initializer.js index 6a51c161..86ee586f 100644 --- a/src/utils/initializer.js +++ b/src/utils/initializer.js @@ -12,7 +12,6 @@ module.exports = function initializer(defaults) { settingsComponentObjects, selectors, styleConfig: defaultStyleConfig, - pageProperties: defaultPageProperties, ...defaultInitialState } = defaults; @@ -23,7 +22,6 @@ module.exports = function initializer(defaults) { events: userEvents = {}, sortProperties = {}, styleConfig: userStyleConfig = {}, - pageProperties: userPageProperties, components: userComponents, renderProperties: userRenderProperties = {}, settingsComponentObjects: userSettingsComponentObjects, @@ -61,7 +59,6 @@ module.exports = function initializer(defaults) { ...plugins.map(p => p.styleConfig), userStyleConfig); - const pageProperties = Object.assign({}, defaultPageProperties, userPageProperties); // TODO: This should also look at the default and plugin initial state objects const renderProperties = Object.assign({ @@ -76,7 +73,6 @@ module.exports = function initializer(defaults) { userInitialState, { data, - pageProperties, renderProperties, sortProperties, styleConfig, From 5e6b45770d4919ba8f17587d770115bfdd51945f Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Sun, 24 Sep 2017 21:07:48 -0500 Subject: [PATCH 14/27] Avoid special treatment for sortProperties --- src/module.d.ts | 2 +- src/utils/__tests__/initilizerTests.js | 1 - src/utils/initializer.js | 2 -- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/module.d.ts b/src/module.d.ts index 84bfd841..f89eba0b 100644 --- a/src/module.d.ts +++ b/src/module.d.ts @@ -385,6 +385,7 @@ interface GriddleInitialState { enableSettings?: boolean; pageProperties?: GriddlePageProperties; sortMethod?: (data: any[], column: string, sortAscending?: boolean) => number; + sortProperties?: GriddleSortKey[]; textProperties?: { next?: string, previous?: string, @@ -402,7 +403,6 @@ export interface GriddlePlugin extends GriddleExtensibility { export interface GriddleProps extends GriddlePlugin, GriddleInitialState { plugins?: GriddlePlugin[]; data?: T[]; - sortProperties?: GriddleSortKey[]; storeKey?: string; } diff --git a/src/utils/__tests__/initilizerTests.js b/src/utils/__tests__/initilizerTests.js index f54318f4..229103a3 100644 --- a/src/utils/__tests__/initilizerTests.js +++ b/src/utils/__tests__/initilizerTests.js @@ -11,7 +11,6 @@ const expectedDefaultInitialState = { rowProperties: null, columnProperties: {}, }, - sortProperties: {}, styleConfig: {}, }; diff --git a/src/utils/initializer.js b/src/utils/initializer.js index 86ee586f..e53d137d 100644 --- a/src/utils/initializer.js +++ b/src/utils/initializer.js @@ -20,7 +20,6 @@ module.exports = function initializer(defaults) { data = [], children: rowPropertiesComponent, events: userEvents = {}, - sortProperties = {}, styleConfig: userStyleConfig = {}, components: userComponents, renderProperties: userRenderProperties = {}, @@ -74,7 +73,6 @@ module.exports = function initializer(defaults) { { data, renderProperties, - sortProperties, styleConfig, } ); From 8bff341f7250e1e54f3b6694269fcf6f21375232 Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Sun, 24 Sep 2017 22:24:36 -0500 Subject: [PATCH 15/27] Test initializer reducers --- src/utils/__tests__/initilizerTests.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/utils/__tests__/initilizerTests.js b/src/utils/__tests__/initilizerTests.js index 229103a3..a098106e 100644 --- a/src/utils/__tests__/initilizerTests.js +++ b/src/utils/__tests__/initilizerTests.js @@ -211,3 +211,28 @@ test('init returns expected extra initialState given props (plugins, user)', (as plugin: 1, }); }); + +test('init returns composed reducer given plugins', (assert) => { + const ctx = { + props: { + plugins: [ + { reducer: { PLUGIN: () => ({ plugin: 0 }) } }, + { reducer: { PLUGIN: () => ({ plugin: 1 }) } }, + ], + }, + }; + const defaults = { + reducers: { + DEFAULTS: () => ({ defaults: true }), + PLUGIN: () => ({ plugin: false }), + }, + }; + + const res = init.call(ctx, defaults); + assert.truthy(res); + + assert.is(typeof res.reducers, 'function'); + assert.deepEqual(Object.keys(res.reducers), ['DEFAULTS', 'PLUGIN']); + assert.deepEqual(res.reducers({}, { type: 'DEFAULTS' }), { defaults: true }); + assert.deepEqual(res.reducers({}, { type: 'PLUGIN' }), { plugin: 1 }); +}); From 9eec4962f1166104b5cb459e8b2ab8a259dea679 Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Sun, 24 Sep 2017 22:37:50 -0500 Subject: [PATCH 16/27] Test initializer reduxMiddleware --- src/utils/__tests__/initilizerTests.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/utils/__tests__/initilizerTests.js b/src/utils/__tests__/initilizerTests.js index a098106e..e65f2642 100644 --- a/src/utils/__tests__/initilizerTests.js +++ b/src/utils/__tests__/initilizerTests.js @@ -1,4 +1,5 @@ import test from 'ava'; +import _ from 'lodash'; import init from '../initializer'; @@ -236,3 +237,25 @@ test('init returns composed reducer given plugins', (assert) => { assert.deepEqual(res.reducers({}, { type: 'DEFAULTS' }), { defaults: true }); assert.deepEqual(res.reducers({}, { type: 'PLUGIN' }), { plugin: 1 }); }); + +test('init returns flattened/compacted reduxMiddleware given plugins', (assert) => { + const mw = _.range(0, 4).map(i => () => i); + const ctx = { + props: { + plugins: [ + {}, + { reduxMiddleware: [mw[0]] }, + {}, + { reduxMiddleware: [null, mw[1], undefined, mw[2], null] }, + {}, + ], + reduxMiddleware: [mw[3]], + }, + }; + const defaults = {}; + + const res = init.call(ctx, defaults); + assert.truthy(res); + + assert.deepEqual(res.reduxMiddleware, mw); +}); From bc60559c389e320319a15844c7cec894755250e6 Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Sun, 24 Sep 2017 22:40:31 -0500 Subject: [PATCH 17/27] Guard against invalid props-specified reduxMiddleware --- src/utils/__tests__/initilizerTests.js | 2 +- src/utils/initializer.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/utils/__tests__/initilizerTests.js b/src/utils/__tests__/initilizerTests.js index e65f2642..1b549416 100644 --- a/src/utils/__tests__/initilizerTests.js +++ b/src/utils/__tests__/initilizerTests.js @@ -249,7 +249,7 @@ test('init returns flattened/compacted reduxMiddleware given plugins', (assert) { reduxMiddleware: [null, mw[1], undefined, mw[2], null] }, {}, ], - reduxMiddleware: [mw[3]], + reduxMiddleware: [null, mw[3], undefined], }, }; const defaults = {}; diff --git a/src/utils/initializer.js b/src/utils/initializer.js index e53d137d..f524edba 100644 --- a/src/utils/initializer.js +++ b/src/utils/initializer.js @@ -83,9 +83,9 @@ module.exports = function initializer(defaults) { return { initialState, reducers, - reduxMiddleware: [ - ..._.compact(_.flatten(plugins.map(p => p.reduxMiddleware))), + reduxMiddleware: _.compact([ + ..._.flatten(plugins.map(p => p.reduxMiddleware)), ...reduxMiddleware - ], + ]), }; }; From 1c0e5b2eef223e99173ac146e3d38819e3a07063 Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Sun, 24 Sep 2017 22:48:08 -0500 Subject: [PATCH 18/27] Test initializer components --- src/utils/__tests__/initilizerTests.js | 27 ++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/utils/__tests__/initilizerTests.js b/src/utils/__tests__/initilizerTests.js index 1b549416..f18120d8 100644 --- a/src/utils/__tests__/initilizerTests.js +++ b/src/utils/__tests__/initilizerTests.js @@ -259,3 +259,30 @@ test('init returns flattened/compacted reduxMiddleware given plugins', (assert) assert.deepEqual(res.reduxMiddleware, mw); }); + +test('init sets context.components as expected given plugins', (assert) => { + const ctx = { + props: { + plugins: [ + { components: { Plugin: 0, User: false } }, + { components: { Plugin: 1 } }, + ], + components: { User: true }, + }, + }; + const defaults = { + components: { + Defaults: true, + Plugin: false, + }, + }; + + const res = init.call(ctx, defaults); + assert.truthy(res); + + assert.deepEqual(ctx.components, { + Defaults: true, + Plugin: 1, + User: true, + }); +}); From cee63fbd038a5103b10a817614b3852f465c4812 Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Sun, 24 Sep 2017 23:33:47 -0500 Subject: [PATCH 19/27] Test initializer settingsComponentObjects --- src/utils/__tests__/initilizerTests.js | 27 ++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/utils/__tests__/initilizerTests.js b/src/utils/__tests__/initilizerTests.js index f18120d8..d7f7bd1f 100644 --- a/src/utils/__tests__/initilizerTests.js +++ b/src/utils/__tests__/initilizerTests.js @@ -286,3 +286,30 @@ test('init sets context.components as expected given plugins', (assert) => { User: true, }); }); + +test('init sets context.settingsComponentObjects as expected given plugins', (assert) => { + const ctx = { + props: { + plugins: [ + { settingsComponentObjects: { Plugin: 0, User: false } }, + { settingsComponentObjects: { Plugin: 1 } }, + ], + settingsComponentObjects: { User: true }, + }, + }; + const defaults = { + settingsComponentObjects: { + Defaults: true, + Plugin: false, + }, + }; + + const res = init.call(ctx, defaults); + assert.truthy(res); + + assert.deepEqual(ctx.settingsComponentObjects, { + Defaults: true, + Plugin: 1, + User: true, + }); +}); From 0576fbb4b6a90b5015c4dc9c45c96063ab859abe Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Sun, 24 Sep 2017 23:34:22 -0500 Subject: [PATCH 20/27] Test initializer events (bugs?!) --- src/utils/__tests__/initilizerTests.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/utils/__tests__/initilizerTests.js b/src/utils/__tests__/initilizerTests.js index d7f7bd1f..892723d4 100644 --- a/src/utils/__tests__/initilizerTests.js +++ b/src/utils/__tests__/initilizerTests.js @@ -313,3 +313,27 @@ test('init sets context.settingsComponentObjects as expected given plugins', (as User: true, }); }); + +test('init sets context.events as expected given plugins', (assert) => { + const ctx = { + props: { + plugins: [ + { events: { Plugin: 0, User: false } }, + { events: { Plugin: 1 } }, + ], + events: { User: true, User2: true }, + }, + }; + const defaults = { + // TODO: bug that defaultEvents is not used? + }; + + const res = init.call(ctx, defaults); + assert.truthy(res); + + assert.deepEqual(ctx.events, { + Plugin: 1, + User: false, // TODO: bug that plugins overwrite user events? + User2: true, + }); +}); From 3811319624bf374741f1b33a0e76b36eb8c94e74 Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Sun, 24 Sep 2017 23:39:30 -0500 Subject: [PATCH 21/27] Test initializer selectors --- src/utils/__tests__/initilizerTests.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/utils/__tests__/initilizerTests.js b/src/utils/__tests__/initilizerTests.js index 892723d4..1a86537d 100644 --- a/src/utils/__tests__/initilizerTests.js +++ b/src/utils/__tests__/initilizerTests.js @@ -337,3 +337,28 @@ test('init sets context.events as expected given plugins', (assert) => { User2: true, }); }); + +test('init sets context.selectors as expected given plugins', (assert) => { + const ctx = { + props: { + plugins: [ + { selectors: { Plugin: 0 } }, + { selectors: { Plugin: 1 } }, + ], + }, + }; + const defaults = { + selectors: { + Defaults: true, + Plugin: false, + }, + }; + + const res = init.call(ctx, defaults); + assert.truthy(res); + + assert.deepEqual(ctx.selectors, { + Defaults: true, + Plugin: 1, + }); +}); From 764a47edddd302a6f66840f7dd5f1190f5493c45 Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Thu, 19 Oct 2017 00:49:42 -0500 Subject: [PATCH 22/27] Remove unused defaultEvents --- src/index.js | 8 -------- src/utils/__tests__/initilizerTests.js | 4 +--- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/src/index.js b/src/index.js index c99435df..15744a67 100644 --- a/src/index.js +++ b/src/index.js @@ -10,17 +10,9 @@ import settingsComponentObjects from './settingsComponentObjects'; import * as selectors from './selectors/dataSelectors'; import init from './utils/initializer'; -import { setSortProperties } from './utils/sortUtils'; import { StoreListener } from './utils/listenerUtils'; import * as actions from './actions'; -const defaultEvents = { - ...actions, - onFilter: actions.setFilter, - setSortProperties -}; - - const defaultStyleConfig = { icons: { TableHeadingCell: { diff --git a/src/utils/__tests__/initilizerTests.js b/src/utils/__tests__/initilizerTests.js index 1a86537d..4d518746 100644 --- a/src/utils/__tests__/initilizerTests.js +++ b/src/utils/__tests__/initilizerTests.js @@ -324,9 +324,7 @@ test('init sets context.events as expected given plugins', (assert) => { events: { User: true, User2: true }, }, }; - const defaults = { - // TODO: bug that defaultEvents is not used? - }; + const defaults = {}; const res = init.call(ctx, defaults); assert.truthy(res); From 5f1e8eda31ba498c2e432e51d560d5497636cc30 Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Thu, 19 Oct 2017 00:50:48 -0500 Subject: [PATCH 23/27] Test initializer listeners --- src/utils/__tests__/initilizerTests.js | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/utils/__tests__/initilizerTests.js b/src/utils/__tests__/initilizerTests.js index 4d518746..bb169146 100644 --- a/src/utils/__tests__/initilizerTests.js +++ b/src/utils/__tests__/initilizerTests.js @@ -360,3 +360,29 @@ test('init sets context.selectors as expected given plugins', (assert) => { Plugin: 1, }); }); + + +test('init sets context.listeners as expected given props (plugins, user)', (assert) => { + const ctx = { + props: { + plugins: [ + { listeners: { plugin: () => 0, user: () => false } }, + { listeners: { plugin: () => 1 } }, + ], + listeners: { + user: () => true, + user2: () => true, + }, + }, + }; + const defaults = {}; + + const res = init.call(ctx, defaults); + assert.truthy(res); + assert.truthy(res); + + assert.false('defaults' in ctx.listeners); + assert.deepEqual(ctx.listeners.plugin(), 1); + assert.deepEqual(ctx.listeners.user(), false); // TODO: bug that plugins overwrite user listeners? + assert.deepEqual(ctx.listeners.user2(), true); +}); From 227e35bdf94064eda9a59cc8eb8a880a792cc594 Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Thu, 19 Oct 2017 08:46:48 -0500 Subject: [PATCH 24/27] Fix deferred load setState warning --- stories/index.tsx | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/stories/index.tsx b/stories/index.tsx index 58be9ea2..9193c4a4 100644 --- a/stories/index.tsx +++ b/stories/index.tsx @@ -97,16 +97,27 @@ storiesOf('Griddle main', module) }) .add('with local, delayed data', () => { class DeferredGriddle extends React.Component, { data?: FakeData[] }> { + private timeout; + constructor(props) { super(props); this.state = {}; + } + + componentDidMount() { this.resetData(); } + componentWillUnmount() { + this.timeout && clearTimeout(this.timeout); + } + resetData = () => { this.setState({ data: null }); - setTimeout(() => { + this.timeout && clearTimeout(this.timeout); + + this.timeout = setTimeout(() => { this.setState({ data: this.props.data }); }, 2000); } From 3577f8fbeaf480f316e29e0f701acfcf108637c7 Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Thu, 19 Oct 2017 19:31:20 -0500 Subject: [PATCH 25/27] Extract core plugin-ish --- src/core/index.js | 15 +++++++++++ src/core/initialState.js | 45 +++++++++++++++++++++++++++++++ src/index.js | 57 +++------------------------------------- stories/index.tsx | 13 +++++++++ 4 files changed, 76 insertions(+), 54 deletions(-) create mode 100644 src/core/index.js create mode 100644 src/core/initialState.js diff --git a/src/core/index.js b/src/core/index.js new file mode 100644 index 00000000..1b70a240 --- /dev/null +++ b/src/core/index.js @@ -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; diff --git a/src/core/initialState.js b/src/core/initialState.js new file mode 100644 index 00000000..8f329ae0 --- /dev/null +++ b/src/core/initialState.js @@ -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' + }, +}; diff --git a/src/index.js b/src/index.js index 15744a67..c6add4fc 100644 --- a/src/index.js +++ b/src/index.js @@ -4,46 +4,11 @@ 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 corePlugin from './core'; import init from './utils/initializer'; import { StoreListener } from './utils/listenerUtils'; import * as actions from './actions'; -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, @@ -58,27 +23,11 @@ class Griddle extends Component { super(props); const { + core = corePlugin, storeKey = Griddle.storeKey || 'store', } = props; - const { initialState, reducers, reduxMiddleware } = init.call(this, { - reducers: dataReducers, - components, - settingsComponentObjects, - selectors, - styleConfig: defaultStyleConfig, - - pageProperties: { - currentPage: 1, - pageSize: 10 - }, - enableSettings: true, - textProperties: { - next: 'Next', - previous: 'Previous', - settingsToggle: 'Settings' - }, - }); + const { initialState, reducers, reduxMiddleware } = init.call(this, core); const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose this.store = createStore( diff --git a/stories/index.tsx b/stories/index.tsx index 9193c4a4..df40d841 100644 --- a/stories/index.tsx +++ b/stories/index.tsx @@ -1638,6 +1638,19 @@ storiesOf('Settings', module) ); }) +storiesOf('core', module) + .add('Can replace core', () => { + const core = { + components: { + Layout: () =>

Core Replaced!

, + }, + }; + + return ( + + ); + }) + storiesOf('TypeScript', module) .add('GriddleComponent accepts expected types', () => { class Custom extends React.Component<{ value }> { From 1ddd84f905f708c67b8903fc68f4095b136aea9b Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Fri, 20 Oct 2017 13:46:11 -0500 Subject: [PATCH 26/27] Handle null core --- src/index.js | 4 ++++ src/utils/__tests__/initilizerTests.js | 21 +++++++++++++++++++++ src/utils/initializer.js | 2 +- stories/index.tsx | 5 +++++ 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/index.js b/src/index.js index c6add4fc..4b6e0eff 100644 --- a/src/index.js +++ b/src/index.js @@ -79,6 +79,10 @@ class Griddle extends Component { } render() { + if (!this.components.Layout) { + return null; + } + return ( diff --git a/src/utils/__tests__/initilizerTests.js b/src/utils/__tests__/initilizerTests.js index bb169146..31522b38 100644 --- a/src/utils/__tests__/initilizerTests.js +++ b/src/utils/__tests__/initilizerTests.js @@ -15,6 +15,27 @@ const expectedDefaultInitialState = { styleConfig: {}, }; +test('init succeeds given null defaults and empty props', (assert) => { + const ctx = { props: {} }; + const defaults = null; + + const res = init.call(ctx, defaults); + assert.truthy(res); + + assert.deepEqual(res.initialState, expectedDefaultInitialState); + + assert.is(typeof res.reducers, 'function'); + assert.deepEqual(res.reducers({}, { type: 'REDUCE' }), {}); + + assert.deepEqual(res.reduxMiddleware, []); + + assert.deepEqual(ctx.components, {}); + assert.deepEqual(ctx.settingsComponentObjects, {}); + assert.deepEqual(ctx.events, {}); + assert.deepEqual(ctx.selectors, {}); + assert.deepEqual(ctx.listeners, {}); +}); + test('init succeeds given empty defaults and props', (assert) => { const ctx = { props: {} }; const defaults = {}; diff --git a/src/utils/initializer.js b/src/utils/initializer.js index f524edba..193c7e86 100644 --- a/src/utils/initializer.js +++ b/src/utils/initializer.js @@ -13,7 +13,7 @@ module.exports = function initializer(defaults) { selectors, styleConfig: defaultStyleConfig, ...defaultInitialState - } = defaults; + } = defaults || {}; const { plugins = [], diff --git a/stories/index.tsx b/stories/index.tsx index df40d841..46531895 100644 --- a/stories/index.tsx +++ b/stories/index.tsx @@ -1650,6 +1650,11 @@ storiesOf('core', module) ); }) + .add('Can handle null core', () => { + return ( + + ); + }) storiesOf('TypeScript', module) .add('GriddleComponent accepts expected types', () => { From d2931e9cec2b59612119cdb7d3560c19005c057a Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Fri, 20 Oct 2017 14:00:09 -0500 Subject: [PATCH 27/27] Export CorePlugin; add to types --- src/module.d.ts | 3 +++ src/module.js | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/module.d.ts b/src/module.d.ts index f89eba0b..0fb8bb09 100644 --- a/src/module.d.ts +++ b/src/module.d.ts @@ -401,6 +401,7 @@ export interface GriddlePlugin extends GriddleExtensibility { } export interface GriddleProps extends GriddlePlugin, GriddleInitialState { + core?: GriddlePlugin; plugins?: GriddlePlugin[]; data?: T[]; storeKey?: string; @@ -441,6 +442,8 @@ export namespace utils { } export namespace plugins { + var CorePlugin : GriddlePlugin; + var LegacyStylePlugin : GriddlePlugin; var LocalPlugin : GriddlePlugin; diff --git a/src/module.js b/src/module.js index a5d36a0c..1a1c04f8 100644 --- a/src/module.js +++ b/src/module.js @@ -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,