mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Simplified form schema structure and mocks
Keyed by URL instead of anonymous object maps which need to be iterated on Removed the 'schema.forms' namespace, unnecessary since all 'schema' items should be forms
This commit is contained in:
parent
0ca090a391
commit
b4e6d498c9
@ -39,6 +39,17 @@ class CampaignAdmin extends LeftAndMain implements PermissionProvider {
|
||||
}
|
||||
|
||||
public function getClientConfig() {
|
||||
return array_merge(parent::getClientConfig(), [
|
||||
'forms' => [
|
||||
// TODO Use schemaUrl instead
|
||||
'editForm' => [
|
||||
'schemaUrl' => $this->Link('schema/EditForm')
|
||||
]
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
public function schema($request) {
|
||||
// TODO Hardcoding schema until we can get GridField to generate a schema dynamically
|
||||
$json = <<<JSON
|
||||
{
|
||||
@ -137,18 +148,15 @@ class CampaignAdmin extends LeftAndMain implements PermissionProvider {
|
||||
}
|
||||
JSON;
|
||||
|
||||
return array_merge(parent::getClientConfig(), [
|
||||
'forms' => [
|
||||
'editForm' => [
|
||||
// TODO Use schemaUrl instead
|
||||
'schema' => json_decode($json)
|
||||
]
|
||||
]
|
||||
]);
|
||||
$formName = $request->param('ID');
|
||||
if($formName == 'EditForm') {
|
||||
$response = $this->getResponse();
|
||||
$response->addHeader('Content-Type', 'application/json');
|
||||
$response->setBody($json);
|
||||
return $response;
|
||||
} else {
|
||||
return parent::schema($request);
|
||||
}
|
||||
|
||||
public function getEditForm($id = null, $fields = null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -6,9 +6,11 @@ import reducerRegister from 'reducer-register';
|
||||
|
||||
import * as configActions from '../state/config/actions';
|
||||
import ConfigReducer from '../state/config/reducer';
|
||||
import SchemaReducer from '../state/schema/reducer';
|
||||
|
||||
function appBoot() {
|
||||
reducerRegister.add('config', ConfigReducer);
|
||||
reducerRegister.add('schemas', SchemaReducer);
|
||||
|
||||
const initialState = {};
|
||||
const rootReducer = combineReducers(reducerRegister.getAll());
|
||||
|
@ -14,7 +14,7 @@ Actions the component can dispatch. This should include but is not limited to:
|
||||
|
||||
An action to call when the response from fetching schema data is returned. This would normally be a simple action to set the store's `schema` key to the returned data.
|
||||
|
||||
### formSchemaUrl
|
||||
### schemaUrl
|
||||
|
||||
The schema URL where the form will be scaffolded from e.g. '/admin/pages/schema/1'.
|
||||
|
||||
|
@ -6,6 +6,8 @@ import * as schemaActions from '../../state/schema/actions';
|
||||
import SilverStripeComponent from '../../SilverStripeComponent';
|
||||
import FormComponent from '../form';
|
||||
import TextField from '../text-field';
|
||||
import HiddenField from '../hidden-field';
|
||||
import GridField from '../../sections/grid-field';
|
||||
|
||||
// Using this to map field types to components until we implement dependency injection.
|
||||
var fakeInjector = {
|
||||
@ -14,7 +16,9 @@ var fakeInjector = {
|
||||
* Components registered with the fake DI container.
|
||||
*/
|
||||
components: {
|
||||
'TextField': TextField
|
||||
'TextField': TextField,
|
||||
'GridField': GridField,
|
||||
'HiddenField': HiddenField
|
||||
},
|
||||
|
||||
/**
|
||||
@ -42,7 +46,7 @@ var fakeInjector = {
|
||||
case 'String':
|
||||
return this.components.TextField;
|
||||
case 'Hidden':
|
||||
return this.components.TextField;
|
||||
return this.components.HiddenField;
|
||||
case 'Text':
|
||||
// Textarea field (not implemented)
|
||||
return null;
|
||||
@ -73,6 +77,8 @@ var fakeInjector = {
|
||||
case 'Boolean':
|
||||
// Checkbox field (not implemented)
|
||||
return null;
|
||||
case 'Custom':
|
||||
return this.components.GridField;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
@ -117,7 +123,7 @@ export class FormBuilderComponent extends SilverStripeComponent {
|
||||
this.formSchemaPromise = $.ajax({
|
||||
method: 'GET',
|
||||
headers: { 'X-FormSchema-Request': headerValues.join() },
|
||||
url: this.props.formSchemaUrl
|
||||
url: this.props.schemaUrl
|
||||
}).done((data, status, xhr) => {
|
||||
this.isFetching = false;
|
||||
this.props.actions.setSchema(data);
|
||||
@ -128,17 +134,6 @@ export class FormBuilderComponent extends SilverStripeComponent {
|
||||
return this.formSchemaPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets form schema for the FormBuilder.
|
||||
*
|
||||
* @return object|undefined
|
||||
*/
|
||||
getFormSchema() {
|
||||
return this.props.schema.forms.find(function (form) {
|
||||
return form.schema.schema_url === this.props.formSchemaUrl;
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a list of schema fields to their React Component.
|
||||
* Only top level form fields are handled here, composite fields (TabSets etc),
|
||||
@ -189,19 +184,19 @@ export class FormBuilderComponent extends SilverStripeComponent {
|
||||
}
|
||||
|
||||
render() {
|
||||
const schema = this.props.schemas[this.props.schemaUrl];
|
||||
|
||||
// If the response from fetching the initial data
|
||||
// hasn't come back yet, don't render anything.
|
||||
if (this.props.schema.forms.length === 0) {
|
||||
if (!schema) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const schema = this.getFormSchema().schema;
|
||||
|
||||
const formProps = {
|
||||
actions: schema.actions,
|
||||
attributes: schema.attributes,
|
||||
data: schema.data,
|
||||
fields: schema.fields,
|
||||
actions: schema.schema.actions,
|
||||
attributes: schema.schema.attributes,
|
||||
data: schema.schema.data,
|
||||
fields: schema.schema.fields,
|
||||
mapFieldsToComponents: this.mapFieldsToComponents
|
||||
};
|
||||
|
||||
@ -211,13 +206,13 @@ export class FormBuilderComponent extends SilverStripeComponent {
|
||||
|
||||
FormBuilderComponent.propTypes = {
|
||||
actions: React.PropTypes.object.isRequired,
|
||||
formSchemaUrl: React.PropTypes.string.isRequired,
|
||||
schema: React.PropTypes.object.isRequired
|
||||
schemaUrl: React.PropTypes.string.isRequired,
|
||||
schemas: React.PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
schema: state.schema
|
||||
schemas: state.schemas
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@ describe('FormBuilderComponent', () => {
|
||||
getState: () => {}
|
||||
},
|
||||
actions: {},
|
||||
formSchemaUrl: 'admin/assets/schema/1',
|
||||
schemaUrl: 'admin/assets/schema/1',
|
||||
schema: { forms: [{ schema: { id: '1', schema_url: 'admin/assets/schema/1' } }] }
|
||||
};
|
||||
|
||||
|
@ -43,10 +43,10 @@ class FormComponent extends SilverStripeComponent {
|
||||
}
|
||||
|
||||
FormComponent.propTypes = {
|
||||
actions: React.PropTypes.array.isRequired,
|
||||
actions: React.PropTypes.array,
|
||||
attributes: React.PropTypes.shape({
|
||||
action: React.PropTypes.string.isRequired,
|
||||
className: React.PropTypes.string.isRequired,
|
||||
'class': React.PropTypes.string.isRequired,
|
||||
enctype: React.PropTypes.string.isRequired,
|
||||
id: React.PropTypes.string.isRequired,
|
||||
method: React.PropTypes.string.isRequired
|
||||
|
@ -5,6 +5,7 @@ import ActionButton from 'action-button';
|
||||
import i18n from 'i18n';
|
||||
import NorthHeader from 'north-header';
|
||||
import GridField from 'grid-field';
|
||||
import FormBuilder from '../../components/form-builder';
|
||||
|
||||
class CampaignAdminContainer extends SilverStripeComponent {
|
||||
|
||||
@ -15,17 +16,17 @@ class CampaignAdminContainer extends SilverStripeComponent {
|
||||
}
|
||||
|
||||
render() {
|
||||
const schemaUrl = this.props.config.forms.editForm.schemaUrl;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<NorthHeader />
|
||||
|
||||
<ActionButton
|
||||
text={i18n._t('Campaigns.ADDCAMPAIGN')}
|
||||
type={'secondary'}
|
||||
icon={'plus-circled'}
|
||||
handleClick={this.addCampaign} />
|
||||
|
||||
<GridField />
|
||||
<FormBuilder schemaUrl={schemaUrl} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import ACTION_TYPES from './action-types';
|
||||
|
||||
/**
|
||||
* Sets the schema being used to generate the curent layout.
|
||||
* Sets the schema being used to generate the current form layout.
|
||||
*
|
||||
* @param string schema - JSON schema for the layout.
|
||||
*/
|
||||
|
@ -1,30 +1,15 @@
|
||||
import deepFreeze from 'deep-freeze';
|
||||
import ACTION_TYPES from './action-types';
|
||||
|
||||
const initialState = deepFreeze({
|
||||
forms: []
|
||||
});
|
||||
const initialState = deepFreeze({});
|
||||
|
||||
export default function schemaReducer(state = initialState, action = null) {
|
||||
|
||||
switch (action.type) {
|
||||
|
||||
case ACTION_TYPES.SET_SCHEMA:
|
||||
if (state.forms.length === 0) {
|
||||
return deepFreeze(Object.assign({}, state, { forms: [action.payload] }));
|
||||
}
|
||||
|
||||
// Replace the form which has a matching `schema.id` property.
|
||||
return deepFreeze(Object.assign({}, state, {
|
||||
forms: state.forms.map((form) => {
|
||||
if (form.schema.id === action.payload.schema.id) {
|
||||
// Only replace the `schema` key incase other actions have updated other keys.
|
||||
return Object.assign({}, form, action.payload);
|
||||
}
|
||||
|
||||
return form;
|
||||
})
|
||||
}));
|
||||
const id = action.payload.schema.schema_url;
|
||||
return deepFreeze(Object.assign({}, state, {[id]: action.payload}));
|
||||
|
||||
default:
|
||||
return state;
|
||||
|
2
admin/templates/Includes/CampaignAdmin_Content.ss
Normal file
2
admin/templates/Includes/CampaignAdmin_Content.ss
Normal file
@ -0,0 +1,2 @@
|
||||
<div class="cms-content center $BaseCSSClasses" data-layout-type="border" data-pjax-fragment="Content">
|
||||
</div>
|
Loading…
Reference in New Issue
Block a user