Skip to content

Commit

Permalink
WIP: Pulls/4/react dependency injection (#70)
Browse files Browse the repository at this point in the history
* initial build

* provide injector

* Context working

* it works

* add bottle js, new API

* Refine public API

* Proof of concepts working, API finalised

* rebase

* Several revisions to API, test suite

* build

* New test, linting

* New transform() API, before/after rules cleanup

* Allow strings as dependencies in inject(), not just arrays

* Linting errors in test
  • Loading branch information
Aaron Carlino authored May 26, 2017
1 parent e3b4b9e commit df72497
Show file tree
Hide file tree
Showing 18 changed files with 2,547 additions and 1,795 deletions.
5 changes: 5 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,10 @@
},
"rules": {
"init-declarations": 1
},
"parserOptions": {
"ecmaFeatures": {
"experimentalObjectRestSpread": true
}
}
}
543 changes: 308 additions & 235 deletions client/dist/js/bundle.js

Large diffs are not rendered by default.

2,376 changes: 1,188 additions & 1,188 deletions client/dist/js/vendor.js

Large diffs are not rendered by default.

57 changes: 0 additions & 57 deletions client/src/boot/BootInjector.js

This file was deleted.

10 changes: 7 additions & 3 deletions client/src/boot/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import BootRoutes from './BootRoutes';
import Injector from 'lib/Injector';
import { combineReducers, createStore, applyMiddleware, compose } from 'redux';
import thunkMiddleware from 'redux-thunk';
import { reducer as ReduxFormReducer } from 'redux-form';
Expand All @@ -11,7 +12,7 @@ import SchemaReducer from 'state/schema/SchemaReducer';
import RecordsReducer from 'state/records/RecordsReducer';
import BreadcrumbsReducer from 'state/breadcrumbs/BreadcrumbsReducer';
import UnsavedFormsReducer from 'state/unsavedForms/UnsavedFormsReducer';
import bootInjector from 'boot/BootInjector';
import registerComponents from 'boot/registerComponents';
import TreeDropdownFieldReducer from 'state/treeDropdownField/TreeDropdownFieldReducer';
import ApolloClient, { createNetworkInterface } from 'apollo-client';
import { printRequest } from 'apollo-client/transport/networkInterface';
Expand Down Expand Up @@ -72,7 +73,11 @@ function appBoot() {
reducerRegister.add('treeDropdownField', TreeDropdownFieldReducer);
reducerRegister.add('unsavedForms', UnsavedFormsReducer);

bootInjector.start();
// Force this to the end of the execution queue to ensure it's last.
window.setTimeout(() => {
registerComponents();
Injector.load();
}, 0);

const initialState = {};
const rootReducer = combineReducers(reducerRegister.getAll());
Expand Down Expand Up @@ -125,5 +130,4 @@ function appBoot() {
window.jQuery('body').addClass('js-react-boot');
}
}

window.onload = appBoot;
48 changes: 48 additions & 0 deletions client/src/boot/registerComponents.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import Injector from 'lib/Injector';
import TextField from 'components/TextField/TextField';
import HiddenField from 'components/HiddenField/HiddenField';
import DateField from 'components/DateField/DateField';
import TimeField from 'components/TimeField/TimeField';
import DatetimeField from 'components/DatetimeField/DatetimeField';
import CheckboxField from 'components/CheckboxField/CheckboxField';
import CheckboxSetField from 'components/CheckboxSetField/CheckboxSetField';
import OptionsetField from 'components/OptionsetField/OptionsetField';
import GridField from 'components/GridField/GridField';
import SingleSelectField from 'components/SingleSelectField/SingleSelectField';
import PopoverField from 'components/PopoverField/PopoverField';
import HeaderField from 'components/HeaderField/HeaderField';
import LiteralField from 'components/LiteralField/LiteralField';
import HtmlReadonlyField from 'components/HtmlReadonlyField/HtmlReadonlyField';
import LookupField from 'components/LookupField/LookupField';
import CompositeField from 'components/CompositeField/CompositeField';
import LabelField from 'components/LabelField/LabelField';
import Tabs from 'components/Tabs/Tabs';
import TabItem from 'components/Tabs/TabItem';
import FormAction from 'components/FormAction/FormAction';
import FieldGroup from 'components/FieldGroup/FieldGroup';
import TreeDropdownField from 'components/TreeDropdownField/TreeDropdownField';

export default () => {
Injector.register('TextField', TextField);
Injector.register('HiddenField', HiddenField);
Injector.register('DateField', DateField);
Injector.register('TimeField', TimeField);
Injector.register('DatetimeField', DatetimeField);
Injector.register('CheckboxField', CheckboxField);
Injector.register('CheckboxSetField', CheckboxSetField);
Injector.register('OptionsetField', OptionsetField);
Injector.register('GridField', GridField);
Injector.register('FieldGroup', FieldGroup);
Injector.register('SingleSelectField', SingleSelectField);
Injector.register('PopoverField', PopoverField);
Injector.register('HeaderField', HeaderField);
Injector.register('LiteralField', LiteralField);
Injector.register('HtmlReadonlyField', HtmlReadonlyField);
Injector.register('LookupField', LookupField);
Injector.register('CompositeField', CompositeField);
Injector.register('Tabs', Tabs);
Injector.register('TabItem', TabItem);
Injector.register('FormAction', FormAction);
Injector.register('LabelField', LabelField);
Injector.register('TreeDropdownField', TreeDropdownField);
};
44 changes: 40 additions & 4 deletions client/src/components/FormBuilder/FormBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import schemaFieldValues, { schemaMerge, findField } from 'lib/schemaFieldValues
import SilverStripeComponent from 'lib/SilverStripeComponent';
import Validator from 'lib/Validator';
import backend from 'lib/Backend';
import injector from 'lib/Injector';
import { withInjector } from 'lib/Injector';

class FormBuilder extends SilverStripeComponent {

Expand Down Expand Up @@ -138,8 +138,8 @@ class FormBuilder extends SilverStripeComponent {
let componentProps = props;
// 'component' key is renamed to 'schemaComponent' in normalize*() methods
const SchemaComponent = componentProps.schemaComponent !== null
? injector.getComponentByName(componentProps.schemaComponent)
: injector.getComponentByDataType(componentProps.schemaType);
? this.context.injector.get(componentProps.schemaComponent)
: this.getComponentForDataType(componentProps.schemaType);

if (SchemaComponent === null) {
return null;
Expand Down Expand Up @@ -201,6 +201,42 @@ class FormBuilder extends SilverStripeComponent {
});
}

/**
* Default data type to component mappings.
* Used as a fallback when no component type is provided in the form schema.
*
* @param string dataType - The data type provided by the form schema.
* @return object|null
*/
getComponentForDataType(dataType) {
const { injector: { get } } = this.context;
switch (dataType) {
case 'String':
case 'Text':
return get('TextField');
case 'Date':
return get('DateField');
case 'Time':
return get('TimeField');
case 'Datetime':
return get('DatetimeField');
case 'Hidden':
return get('HiddenField');
case 'SingleSelect':
return get('SingleSelectField');
case 'Custom':
return get('GridField');
case 'Structural':
return get('CompositeField');
case 'Boolean':
return get('CheckboxField');
case 'MultiSelect':
return get('CheckboxSetField');
default:
return null;
}
}

/**
* Maps a list of form actions to their React Component.
*
Expand Down Expand Up @@ -385,4 +421,4 @@ FormBuilder.defaultProps = {
};

export { basePropTypes, schemaPropType };
export default FormBuilder;
export default withInjector(FormBuilder);
8 changes: 5 additions & 3 deletions client/src/containers/App/App.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react';
import SilverStripeComponent from 'lib/SilverStripeComponent';
import { provideInjector } from 'lib/Injector';

/**
* Empty container for the moment, will eventually contain the CMS menu`
Expand All @@ -8,9 +9,10 @@ import SilverStripeComponent from 'lib/SilverStripeComponent';
class App extends SilverStripeComponent {
render() {
// TODO re-add <div className="app"> wrapper when applying to document.body
const Child = React.Children.only(this.props.children);
return (Child);
return <div>{this.props.children}</div>;
// const Child = React.Children.only(this.props.children);
// return (Child);
}
}

export default App;
export default provideInjector(App);
Loading

0 comments on commit df72497

Please sign in to comment.