Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Pulls/4/react dependency injection #70

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yay, great way to solve this (withInjector context HoC)

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>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little cautious of this due to the use of flexbox currently for the App component.

But I know you're aware of it, so I'll leave that to after this pull request is ready :D

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I haven't seen any issues yet, but I have noted it as a temporary hack that needs to be reviewed before merge.

// const Child = React.Children.only(this.props.children);
// return (Child);
}
}

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