/* * Copyright 2007-2017 Charles du Jeu - Abstrium SAS * This file is part of Pydio. * * Pydio is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Pydio 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with Pydio. If not, see . * * The latest code can be found at . */ 'use strict'; exports.__esModule = true; var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } var _GroupSwitchPanel = require('./GroupSwitchPanel'); var _GroupSwitchPanel2 = _interopRequireDefault(_GroupSwitchPanel); var _ReplicationPanel = require('./ReplicationPanel'); var _ReplicationPanel2 = _interopRequireDefault(_ReplicationPanel); var _managerManager = require('../manager/Manager'); var _managerManager2 = _interopRequireDefault(_managerManager); /** * Form Panel is a ready to use form builder inherited for Pydio's legacy parameters formats ('standard form'). * It is very versatile and can basically take a set of parameters defined in the XML manifests (or defined manually * in JS) and display them as a user form. * It is a controlled component: it takes a {values} object and triggers back an onChange() function. * * See also Manager class to get some utilitary functions to parse parameters and extract values for the form. */ var React = require('react'); var ReactMUI = require('material-ui-legacy'); var LangUtils = require('pydio/util/lang'); var PydioApi = require('pydio/http/api'); var _require = require('material-ui'); var Tabs = _require.Tabs; var Tab = _require.Tab; var Paper = _require.Paper; exports['default'] = React.createClass({ displayName: 'FormPanel', _hiddenValues: {}, _internalValid: null, _parametersMetadata: null, propTypes: { /** * Array of Pydio StandardForm parameters */ parameters: React.PropTypes.array.isRequired, /** * Object containing values for the parameters */ values: React.PropTypes.object, /** * Trigger unitary function when one form input changes. */ onParameterChange: React.PropTypes.func, /** * Send all form values onchange, including eventually the removed ones (for dynamic panels) */ onChange: React.PropTypes.func, /** * Triggered when the form globabally switches between valid and invalid state * Triggered once at form construction */ onValidStatusChange: React.PropTypes.func, /** * Disable the whole form at once */ disabled: React.PropTypes.bool, /** * String added to the image inputs for upload/download operations */ binary_context: React.PropTypes.string, /** * 0 by default, subforms will have their zDepth value increased by one */ depth: React.PropTypes.number, /** * Add an additional header component (added inside first subpanel) */ header: React.PropTypes.object, /** * Add an additional footer component (added inside last subpanel) */ footer: React.PropTypes.object, /** * Add other arbitrary panels, either at the top or the bottom */ additionalPanes: React.PropTypes.shape({ top: React.PropTypes.array, bottom: React.PropTypes.array }), /** * An array of tabs containing groupNames. Groups will be splitted * accross those tabs */ tabs: React.PropTypes.array, /** * Fired when a the active tab changes */ onTabChange: React.PropTypes.func, /** * A bit like tabs, but using accordion-like layout */ accordionizeIfGroupsMoreThan: React.PropTypes.number, /** * Forward an event when scrolling the form */ onScrollCallback: React.PropTypes.func, /** * Restrict to a subset of field groups */ limitToGroups: React.PropTypes.array, /** * Ignore some specific fields types */ skipFieldsTypes: React.PropTypes.array, /* Helper Options */ /** * Pass pointers to the Pydio Companion container */ setHelperData: React.PropTypes.func, /** * Function to check if the companion is active or none and if a parameter * has helper data */ checkHasHelper: React.PropTypes.func, /** * Test for parameter */ helperTestFor: React.PropTypes.string }, externallySelectTab: function externallySelectTab(index) { this.setState({ tabSelectedIndex: index }); }, getInitialState: function getInitialState() { if (this.props.onTabChange) return { tabSelectedIndex: 0 }; return {}; }, getDefaultProps: function getDefaultProps() { return { depth: 0, values: {} }; }, componentWillReceiveProps: function componentWillReceiveProps(newProps) { if (JSON.stringify(newProps.parameters) !== JSON.stringify(this.props.parameters)) { this._internalValid = null; this._hiddenValues = {}; this._parametersMetadata = {}; } if (newProps.values && newProps.values !== this.props.values) { this.checkValidStatus(newProps.values); } }, getValues: function getValues() { return this.props.values; //LangUtils.mergeObjectsRecursive(this._hiddenValues, this.props.values); }, onParameterChange: function onParameterChange(paramName, newValue, oldValue) { var additionalFormData = arguments.length <= 3 || arguments[3] === undefined ? null : arguments[3]; // Update writeValues var newValues = LangUtils.deepCopy(this.getValues()); if (this.props.onParameterChange) { this.props.onParameterChange(paramName, newValue, oldValue, additionalFormData); } if (additionalFormData) { if (!this._parametersMetadata) this._parametersMetadata = {}; this._parametersMetadata[paramName] = additionalFormData; } newValues[paramName] = newValue; var dirty = true; this.onChange(newValues, dirty); }, onChange: function onChange(newValues, dirty, removeValues) { if (this.props.onChange) { //newValues = LangUtils.mergeObjectsRecursive(this._hiddenValues, newValues); for (var key in this._hiddenValues) { if (this._hiddenValues.hasOwnProperty(key) && newValues[key] === undefined && (!removeValues || removeValues[key] == undefined)) { newValues[key] = this._hiddenValues[key]; } } this.props.onChange(newValues, dirty, removeValues); } this.checkValidStatus(newValues); }, onSubformChange: function onSubformChange(newValues, dirty, removeValues) { var values = LangUtils.mergeObjectsRecursive(this.getValues(), newValues); if (removeValues) { for (var k in removeValues) { if (removeValues.hasOwnProperty(k) && values[k] !== undefined) { delete values[k]; if (this._hiddenValues[k] !== undefined) { delete this._hiddenValues[k]; } } } } this.onChange(values, dirty, removeValues); }, onSubformValidStatusChange: function onSubformValidStatusChange(newValidValue, failedMandatories) { if ((newValidValue !== this._internalValid || this.props.forceValidStatusCheck) && this.props.onValidStatusChange) { this.props.onValidStatusChange(newValidValue, failedMandatories); } this._internalValid = newValidValue; }, applyButtonAction: function applyButtonAction(parameters, callback) { if (this.props.applyButtonAction) { this.props.applyButtonAction(parameters, callback); return; } parameters = LangUtils.mergeObjectsRecursive(parameters, this.getValuesForPOST(this.getValues())); PydioApi.getClient().request(parameters, callback); }, getValuesForPOST: function getValuesForPOST(values) { var prefix = arguments.length <= 1 || arguments[1] === undefined ? 'DRIVER_OPTION_' : arguments[1]; return _managerManager2['default'].getValuesForPOST(this.props.parameters, values, prefix, this._parametersMetadata); }, checkValidStatus: function checkValidStatus(values) { var failedMandatories = []; this.props.parameters.map((function (p) { if (['string', 'textarea', 'password', 'integer'].indexOf(p.type) > -1 && (p.mandatory == "true" || p.mandatory === true)) { if (!values || !values.hasOwnProperty(p.name) || values[p.name] === undefined || values[p.name] === "") { failedMandatories.push(p); } } if (p.type === 'valid-password' && this.refs['form-element-' + p.name]) { if (!this.refs['form-element-' + p.name].isValid()) { failedMandatories.push(p); } } }).bind(this)); var previousValue, newValue; previousValue = this._internalValid; //(this._internalValid !== undefined ? this._internalValid : true); newValue = failedMandatories.length ? false : true; if ((newValue !== this._internalValid || this.props.forceValidStatusCheck) && this.props.onValidStatusChange) { this.props.onValidStatusChange(newValue, failedMandatories); } this._internalValid = newValue; }, componentDidMount: function componentDidMount() { this.checkValidStatus(this.props.values); }, renderGroupHeader: function renderGroupHeader(groupLabel, accordionize, index, active) { var properties = { key: 'group-' + groupLabel }; if (accordionize) { var current = this.state && this.state.currentActiveGroup ? this.state.currentActiveGroup : null; properties['className'] = 'group-label-' + (active ? 'active' : 'inactive'); properties['onClick'] = (function () { this.setState({ currentActiveGroup: current != index ? index : null }); }).bind(this); groupLabel = [React.createElement('span', { key: 'toggler', className: "group-active-toggler icon-angle-" + (current == index ? 'down' : 'right') }), groupLabel]; } return React.createElement('h' + (3 + this.props.depth), properties, groupLabel); }, render: function render() { var _this = this; var allGroups = []; var values = this.getValues(); var groupsOrdered = ['__DEFAULT__']; allGroups['__DEFAULT__'] = { FIELDS: [] }; var replicationGroups = {}; this.props.parameters.map((function (attributes) { var type = attributes['type']; if (this.props.skipFieldsTypes && this.props.skipFieldsTypes.indexOf(type) > -1) { return; } var paramName = attributes['name']; var field; if (attributes['group_switch_name']) return; var group = attributes['group'] || '__DEFAULT__'; if (!allGroups[group]) { groupsOrdered.push(group); allGroups[group] = { FIELDS: [], LABEL: group }; } var repGroup = attributes['replicationGroup']; if (repGroup) { if (!replicationGroups[repGroup]) { replicationGroups[repGroup] = { PARAMS: [], GROUP: group, POSITION: allGroups[group].FIELDS.length }; allGroups[group].FIELDS.push('REPLICATION:' + repGroup); } // Copy var repAttr = LangUtils.deepCopy(attributes); delete repAttr['replicationGroup']; delete repAttr['group']; replicationGroups[repGroup].PARAMS.push(repAttr); } else { if (type.indexOf("group_switch:") === 0) { field = React.createElement(_GroupSwitchPanel2['default'], _extends({}, this.props, { onChange: this.onSubformChange, paramAttributes: attributes, parameters: this.props.parameters, values: this.props.values, key: paramName, onScrollCallback: null, limitToGroups: null, onValidStatusChange: this.onSubformValidStatusChange })); } else if (attributes['type'] !== 'hidden') { var helperMark; if (this.props.setHelperData && this.props.checkHasHelper && this.props.checkHasHelper(attributes['name'], this.props.helperTestFor)) { var showHelper = (function () { this.props.setHelperData({ paramAttributes: attributes, values: values, postValues: this.getValuesForPOST(values), applyButtonAction: this.applyButtonAction }, this.props.helperTestFor); }).bind(this); helperMark = React.createElement('span', { className: 'icon-question-sign', onClick: showHelper }); } var mandatoryMissing = false; var classLegend = "form-legend"; if (attributes['errorText']) { classLegend = "form-legend mandatory-missing"; } else if (attributes['warningText']) { classLegend = "form-legend warning-message"; } else if (attributes['mandatory'] && (attributes['mandatory'] === "true" || attributes['mandatory'] === true)) { if (['string', 'textarea', 'image', 'integer'].indexOf(attributes['type']) !== -1 && !values[paramName]) { mandatoryMissing = true; classLegend = "form-legend mandatory-missing"; } } var props = { ref: "form-element-" + paramName, attributes: attributes, name: paramName, value: values[paramName], onChange: (function (newValue, oldValue, additionalFormData) { this.onParameterChange(paramName, newValue, oldValue, additionalFormData); }).bind(this), disabled: this.props.disabled || attributes['readonly'], multiple: attributes['multiple'], binary_context: this.props.binary_context, displayContext: 'form', applyButtonAction: this.applyButtonAction, errorText: mandatoryMissing ? pydio.MessageHash['621'] : attributes.errorText ? attributes.errorText : null }; field = React.createElement( 'div', { key: paramName, className: 'form-entry-' + attributes['type'] }, _managerManager2['default'].createFormElement(props), React.createElement( 'div', { className: classLegend }, attributes['warningText'] ? attributes['warningText'] : attributes['description'], ' ', helperMark ) ); } else { this._hiddenValues[paramName] = values[paramName] !== undefined ? values[paramName] : attributes['default']; } if (field) { allGroups[group].FIELDS.push(field); } } }).bind(this)); for (var rGroup in replicationGroups) { if (!replicationGroups.hasOwnProperty(rGroup)) continue; var rGroupData = replicationGroups[rGroup]; allGroups[rGroupData.GROUP].FIELDS[rGroupData.POSITION] = React.createElement(_ReplicationPanel2['default'], _extends({}, this.props, { key: "replication-group-" + rGroupData.PARAMS[0].name, onChange: this.onSubformChange, onParameterChange: null, values: this.getValues(), depth: this.props.depth + 1, parameters: rGroupData.PARAMS, applyButtonAction: this.applyButtonAction, onScrollCallback: null })); } var groupPanes = []; var accordionize = this.props.accordionizeIfGroupsMoreThan && groupsOrdered.length > this.props.accordionizeIfGroupsMoreThan; var currentActiveGroup = this.state && this.state.currentActiveGroup ? this.state.currentActiveGroup : 0; groupsOrdered.map((function (g, gIndex) { if (this.props.limitToGroups && this.props.limitToGroups.indexOf(g) === -1) { return; } var header, gData = allGroups[g]; var className = 'pydio-form-group', active = false; if (accordionize) { active = currentActiveGroup == gIndex; if (gIndex == currentActiveGroup) className += ' form-group-active';else className += ' form-group-inactive'; } if (!gData.FIELDS.length) return; if (gData.LABEL && !(this.props.skipFieldsTypes && this.props.skipFieldsTypes.indexOf('GroupHeader') > -1)) { header = this.renderGroupHeader(gData.LABEL, accordionize, gIndex, active); } if (this.props.depth == 0) { className += ' z-depth-1'; groupPanes.push(React.createElement( Paper, { className: className, key: 'pane-' + g }, gIndex == 0 && this.props.header ? this.props.header : null, header, React.createElement( 'div', null, gData.FIELDS ), gIndex == groupsOrdered.length - 1 && this.props.footer ? this.props.footer : null )); } else { groupPanes.push(React.createElement( 'div', { className: className, key: 'pane-' + g }, gIndex == 0 && this.props.header ? this.props.header : null, header, React.createElement( 'div', null, gData.FIELDS ), gIndex == groupsOrdered.length - 1 && this.props.footer ? this.props.footer : null )); } }).bind(this)); if (this.props.additionalPanes) { (function () { var otherPanes = { top: [], bottom: [] }; var depth = _this.props.depth; var index = 0; var _loop = function (k) { if (!otherPanes.hasOwnProperty(k)) return 'continue'; if (_this.props.additionalPanes[k]) { _this.props.additionalPanes[k].map(function (p) { if (depth == 0) { otherPanes[k].push(React.createElement( Paper, { className: 'pydio-form-group additional', key: 'other-pane-' + index }, p )); } else { otherPanes[k].push(React.createElement( 'div', { className: 'pydio-form-group additional', key: 'other-pane-' + index }, p )); } index++; }); } }; for (var k in otherPanes) { var _ret2 = _loop(k); if (_ret2 === 'continue') continue; } groupPanes = otherPanes['top'].concat(groupPanes).concat(otherPanes['bottom']); })(); } if (this.props.tabs) { var _ret3 = (function () { var className = _this.props.className; var initialSelectedIndex = 0; var i = 0; var tabs = _this.props.tabs.map((function (tDef) { var label = tDef['label']; var groups = tDef['groups']; if (tDef['selected']) { initialSelectedIndex = i; } var panes = groups.map(function (gId) { if (groupPanes[gId]) { return groupPanes[gId]; } else { return null; } }); i++; return React.createElement( Tab, { label: label, key: label, value: this.props.onTabChange ? i - 1 : undefined }, React.createElement( 'div', { className: (className ? className + ' ' : ' ') + 'pydio-form-panel' + (panes.length % 2 ? ' form-panel-odd' : '') }, panes ) ); }).bind(_this)); if (_this.state.tabSelectedIndex !== undefined) { initialSelectedIndex = _this.state.tabSelectedIndex; } return { v: React.createElement( 'div', { className: 'layout-fill vertical-layout tab-vertical-layout' }, React.createElement( Tabs, { ref: 'tabs', initialSelectedIndex: initialSelectedIndex, value: _this.props.onTabChange ? initialSelectedIndex : undefined, onChange: _this.props.onTabChange ? function (i) { _this.setState({ tabSelectedIndex: i });_this.props.onTabChange(i); } : undefined, style: { flex: 1, display: 'flex', flexDirection: 'column' }, contentContainerStyle: { flex: 1, overflowY: 'auto' } }, tabs ) ) }; })(); if (typeof _ret3 === 'object') return _ret3.v; } else { return React.createElement( 'div', { className: (this.props.className ? this.props.className + ' ' : ' ') + 'pydio-form-panel' + (groupPanes.length % 2 ? ' form-panel-odd' : ''), onScroll: this.props.onScrollCallback }, groupPanes ); } } }); module.exports = exports['default'];