/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
/* eslint no-unused-vars: "warn" */
import Component from 'metal-jsx';
import dom from 'metal-dom';
import RuleEditor from '../../components/RuleEditor/RuleEditor.es';
import RuleList from '../../components/RuleList/RuleList.es';
import {Config} from 'metal-state';
import {EventHandler} from 'metal-events';
import {makeFetch} from 'dynamic-data-mapping-form-renderer/js/util/fetch.es';
/**
* Builder.
* @extends Component
*/
class RuleBuilder extends Component {
created() {
this._eventHandler = new EventHandler();
this._fetchDataProvider();
this._fetchRoles();
}
disposeInternal() {
super.disposeInternal();
this._eventHandler.removeAllListeners();
}
render() {
const {
dataProviderInstanceParameterSettingsURL,
dataProviderInstancesURL,
functionsMetadata,
functionsURL,
pages,
spritemap
} = this.props;
const {dataProvider, index, mode, roles, rules} = this.state;
return (
<div class='container'>
{mode === 'create' && (
<RuleEditor
actions={[]}
conditions={[]}
dataProvider={dataProvider}
dataProviderInstanceParameterSettingsURL={
dataProviderInstanceParameterSettingsURL
}
dataProviderInstancesURL={dataProviderInstancesURL}
events={{
ruleAdded: this._handleRuleAdded.bind(this),
ruleCancel: this._handleRuleCanceled.bind(this),
ruleDeleted: this._handleRuleDeleted.bind(this),
ruleEdited: this._handleRuleEdited.bind(this)
}}
functionsMetadata={functionsMetadata}
functionsURL={functionsURL}
key={'create'}
pages={pages}
ref='RuleEditor'
roles={roles}
spritemap={spritemap}
/>
)}
{mode === 'edit' && (
<RuleEditor
dataProvider={dataProvider}
dataProviderInstanceParameterSettingsURL={
dataProviderInstanceParameterSettingsURL
}
dataProviderInstancesURL={dataProviderInstancesURL}
events={{
ruleAdded: this._handleRuleSaved.bind(this),
ruleCancel: this._handleRuleCanceled.bind(this)
}}
functionsMetadata={functionsMetadata}
functionsURL={functionsURL}
key={'edit'}
pages={pages}
ref='RuleEditor'
roles={roles}
rule={rules[index]}
ruleEditedIndex={index}
spritemap={spritemap}
/>
)}
{mode === 'view' && (
<RuleList
dataProvider={dataProvider}
events={{
ruleAdded: this._handleRuleAdded.bind(this),
ruleCancel: this._handleRuleCanceled.bind(this),
ruleDeleted: this._handleRuleDeleted.bind(this),
ruleEdited: this._handleRuleEdited.bind(this)
}}
pages={pages}
ref='RuleList'
roles={roles}
rules={rules}
spritemap={spritemap}
/>
)}
</div>
);
}
rendered() {
const {mode} = this.state;
const {visible} = this.props;
if (visible) {
const addButton = document.querySelector('#addFieldButton');
if (mode === 'create' || mode === 'edit') {
addButton.classList.add('hide');
} else {
addButton.classList.remove('hide');
}
}
}
syncVisible(visible) {
super.syncVisible(visible);
if (visible) {
this._eventHandler.add(
dom.on(
'#addFieldButton',
'click',
this._handleAddRuleClick.bind(this)
)
);
} else {
this._eventHandler.removeAllListeners();
}
}
willReceiveProps({rules}) {
if (rules && rules.newVal) {
this.setState({
rules: rules.newVal
});
}
}
_fetchDataProvider() {
const {dataProviderInstancesURL} = this.props;
makeFetch({
method: 'GET',
url: dataProviderInstancesURL
})
.then(responseData => {
if (!this.isDisposed()) {
this.setState({
dataProvider: responseData.map(data => {
return {
...data,
label: data.name,
value: data.id
};
})
});
}
})
.catch(error => {
throw new Error(error);
});
}
_fetchRoles() {
const {rolesURL} = this.props;
makeFetch({
method: 'GET',
url: rolesURL
})
.then(responseData => {
if (!this.isDisposed()) {
this.setState({
roles: responseData.map(data => {
return {
...data,
label: data.name,
value: data.id
};
})
});
}
})
.catch(error => {
throw new Error(error);
});
}
_handleAddRuleClick(event) {
this._showRuleCreation();
this._hideAddRuleButton(event.delegateTarget);
}
_handleRuleAdded(event) {
this.emit('ruleAdded', {
...event
});
this._showRuleList();
}
_handleRuleCanceled(event) {
const {index} = this.state;
const rules = this.state.rules.map((rule, ruleIndex) => {
return index === ruleIndex ? this.state.originalRule : rule;
});
this.setState({
mode: 'view',
rules
});
}
_handleRuleDeleted({ruleId}) {
this.emit('ruleDeleted', {
ruleId
});
}
_handleRuleEdited({ruleId}) {
const {rules} = this.state;
ruleId = parseInt(ruleId, 10);
this.setState({
index: ruleId,
mode: 'edit',
originalRule: JSON.parse(JSON.stringify(rules[ruleId]))
});
}
_handleRuleSaved(event) {
this.emit('ruleSaved', {
...event,
ruleId: event.ruleEditedIndex
});
this._showRuleList();
}
_hideAddRuleButton(element) {
dom.addClasses(element, 'hide');
}
_setRulesValueFn() {
return this.props.rules;
}
_showRuleCreation() {
this.setState({
mode: 'create'
});
}
_showRuleList() {
this.setState({
mode: 'view'
});
}
}
RuleBuilder.PROPS = {
dataProviderInstanceParameterSettingsURL: Config.string().required(),
dataProviderInstancesURL: Config.string().required(),
functionsMetadata: Config.object({
number: Config.arrayOf(
Config.shapeOf({
label: Config.string(),
name: Config.string(),
parameterTypes: Config.array(),
returnType: Config.string()
})
),
text: Config.arrayOf(
Config.shapeOf({
label: Config.string(),
name: Config.string(),
parameterTypes: Config.array(),
returnType: Config.string()
})
),
user: Config.arrayOf(
Config.shapeOf({
label: Config.string(),
name: Config.string(),
parameterTypes: Config.array(),
returnType: Config.string()
})
)
}),
functionsURL: Config.string().required(),
pages: Config.array().required(),
rolesURL: Config.string().required(),
rules: Config.arrayOf(
Config.shapeOf({
actions: Config.arrayOf(
Config.shapeOf({
action: Config.string(),
label: Config.string(),
target: Config.string()
})
),
conditions: Config.arrayOf(
Config.shapeOf({
operands: Config.arrayOf(
Config.shapeOf({
label: Config.string(),
repeatable: Config.bool(),
type: Config.string(),
value: Config.string()
})
),
operator: Config.string()
})
),
logicalOperator: Config.string()
})
).value([]),
/**
* The path to the SVG spritemap file containing the icons.
* @default undefined
* @instance
* @memberof Form
* @type {!string}
*/
spritemap: Config.string().required()
};
RuleBuilder.STATE = {
dataProvider: Config.arrayOf(
Config.shapeOf({
id: Config.string(),
name: Config.string(),
uuid: Config.string()
})
).internal(),
/**
* @default
* @instance
* @memberof RuleBuilder
*
*/
index: Config.number(),
mode: Config.oneOf(['view', 'edit', 'create']).value('view'),
originalRule: Config.object(),
roles: Config.arrayOf(
Config.shapeOf({
id: Config.string(),
name: Config.string()
})
).internal(),
rules: Config.arrayOf(
Config.shapeOf({
actions: Config.arrayOf(
Config.shapeOf({
action: Config.string(),
label: Config.string(),
target: Config.string()
})
),
conditions: Config.arrayOf(
Config.shapeOf({
operands: Config.arrayOf(
Config.shapeOf({
label: Config.string(),
repeatable: Config.bool(),
type: Config.string(),
value: Config.string()
})
),
operator: Config.string()
})
),
logicalOperator: Config.string()
})
).valueFn('_setRulesValueFn')
};
export default RuleBuilder;
export {RuleBuilder};