537 lines
17 KiB
JavaScript
Raw Normal View History

/*
*
* Home
*
*/
import React from 'react';
import { connect } from 'react-redux';
2017-07-13 16:55:59 +02:00
import { bindActionCreators } from 'redux';
2017-07-17 18:40:11 +02:00
import { createStructuredSelector } from 'reselect';
2017-07-25 17:03:47 +02:00
import {
find,
findIndex,
findKey,
forEach,
get,
2017-08-04 17:47:38 +02:00
has,
2017-07-25 17:03:47 +02:00
isEmpty,
includes,
isObject,
join,
2017-07-25 17:03:47 +02:00
map,
2017-08-03 15:01:56 +02:00
replace,
split,
2017-07-25 17:03:47 +02:00
toNumber,
toLower,
upperCase,
2017-07-25 17:03:47 +02:00
} from 'lodash';
import { FormattedMessage } from 'react-intl';
import Helmet from 'react-helmet';
2017-07-17 18:40:11 +02:00
import { router } from 'app';
2017-07-18 14:07:48 +02:00
2017-07-17 19:19:54 +02:00
// design
import ContentHeader from 'components/ContentHeader';
2017-08-01 15:10:15 +02:00
import Debug from 'components/Debug';
2017-07-18 15:53:56 +02:00
import EditForm from 'components/EditForm';
2017-07-19 13:10:53 +02:00
import HeaderNav from 'components/HeaderNav';
import List from 'components/List';
import RowDatabase from 'components/RowDatabase';
2017-07-17 19:19:54 +02:00
2017-07-19 13:10:53 +02:00
import { makeSelectSections, makeSelectEnvironments } from 'containers/App/selectors';
import selectHome from './selectors';
2017-07-24 11:11:28 +02:00
import {
cancelChanges,
changeDefaultLanguage,
2017-07-25 17:03:47 +02:00
changeInput,
configFetch,
2017-08-03 20:10:35 +02:00
databaseEdit,
2017-08-01 15:10:15 +02:00
databasesFetch,
2017-08-03 17:31:13 +02:00
databaseDelete,
2017-07-25 17:03:47 +02:00
editSettings,
languageDelete,
languagesFetch,
newLanguagePost,
2017-08-03 17:13:25 +02:00
newDatabasePost,
specificDatabaseFetch,
2017-07-24 11:11:28 +02:00
} from './actions'
import styles from './styles.scss';
import config from './config.json';
export class Home extends React.Component { // eslint-disable-line react/prefer-stateless-function
2017-07-18 15:53:56 +02:00
constructor(props) {
super(props);
this.customComponents = config.customComponents;
this.components = {
editForm: EditForm,
list: List,
defaultComponent: HeaderNav,
2017-08-01 15:10:15 +02:00
debug: Debug,
};
// allowing state only for database modal purpose
this.state = {
modal: false,
toggleDefaultConnection: false,
2017-07-18 15:53:56 +02:00
};
}
componentDidMount() {
if (this.props.params.slug) {
this.handleFetch(this.props);
2017-07-17 18:40:11 +02:00
} else {
2017-07-19 13:10:53 +02:00
router.push(`/plugins/settings-manager/${get(this.props.menuSections, ['0', 'items', '0', 'slug'])}`);
}
}
2017-07-13 16:55:59 +02:00
componentWillReceiveProps(nextProps) {
// check if params slug updated
if (this.props.params.slug !== nextProps.params.slug && nextProps.params.slug) {
2017-07-17 18:40:11 +02:00
if (nextProps.params.slug) {
// get data from api if params slug updated
this.handleFetch(nextProps);
2017-07-17 18:40:11 +02:00
} else {
// redirect user if no params slug provided
2017-07-19 13:10:53 +02:00
router.push(`/plugins/settings-manager/${get(this.props.menuSections, ['0', 'items', '0', 'slug'])}`);
2017-07-17 18:40:11 +02:00
}
2017-07-19 13:10:53 +02:00
} else if (this.props.params.env !== nextProps.params.env && nextProps.params.env && this.props.params.env) {
// get data if params env updated
this.handleFetch(nextProps);
2017-07-13 16:55:59 +02:00
}
}
2017-07-17 18:40:11 +02:00
2017-07-25 17:03:47 +02:00
componentDidUpdate(prevProps) {
if (prevProps.home.didCreatedNewLanguage !== this.props.home.didCreatedNewLanguage) {
this.handleFetch(this.props);
}
2017-08-03 17:13:25 +02:00
if (prevProps.home.didCreatedNewDb !== this.props.home.didCreatedNewDb) {
this.handleFetch(this.props);
}
2017-07-25 17:03:47 +02:00
}
/* eslint-disable react/sort-comp */
/* eslint-disable jsx-a11y/no-static-element-interactions */
addConnection = (e) => {
e.preventDefault();
2017-08-03 15:01:56 +02:00
const newData = {};
/* eslint-disable no-template-curly-in-string */
const dbName = get(this.props.home.modifiedData, 'database.connections.${name}.name');
map(this.props.home.modifiedData, (data, key) => {
const k = replace(key, '${name}', dbName);
2017-08-03 17:13:25 +02:00
if (key !== 'database.connections.${name}.name') {
2017-08-03 15:01:56 +02:00
newData[k] = data;
}
});
2017-08-03 17:13:25 +02:00
this.props.newDatabasePost(this.props.params.env, newData);
}
changeDefaultLanguage = ({ target }) => {
// create new object configsDisplay based on store property configsDisplay
const configsDisplay = {
name: this.props.home.configsDisplay.name,
description: this.props.home.configsDisplay.description,
sections: [],
};
// Find the index of the new setted language
const activeLanguageIndex = findIndex(this.props.home.configsDisplay.sections, ['name', target.id]);
forEach(this.props.home.configsDisplay.sections, (section, key) => {
// set all Language active state to false
if (key !== activeLanguageIndex) {
configsDisplay.sections.push({ name: section.name, active: false });
} else {
// set the new language active state to true
configsDisplay.sections.push({ name: section.name, active: true });
}
});
// reset all the configs to ensure component is updated
this.props.changeDefaultLanguage(configsDisplay, target.id);
// format the default locale
const defaultLanguageArray = this.formatLanguageLocale(target.id);
// Edit the new config
this.props.editSettings({ 'language.defaultLocale': join(defaultLanguageArray, '_') }, 'i18n');
}
formatLanguageLocale = (data) => {
const array = [];
forEach(split(data, '_'), (value, key) => {
if (key === 0){
array.push(toLower(value));
} else {
array.push(upperCase(value));
}
});
return array;
}
handleFetch(props) {
2017-08-01 15:10:15 +02:00
const apiUrl = props.params.env ? `${props.params.slug}/${props.params.env}` : props.params.slug;
switch(props.params.slug) {
case 'languages':
return this.props.languagesFetch();
case 'databases':
return this.props.databasesFetch(props.params.env);
default:
return this.props.configFetch(apiUrl);
}
2017-07-13 16:55:59 +02:00
}
2017-07-18 17:52:39 +02:00
handleChange = ({ target }) => {
2017-08-04 17:47:38 +02:00
let value = target.type === 'number' ? toNumber(target.value) : target.value;
let name = target.name;
if (this.props.params.slug === 'security') {
// the only case where the input doesn't have a name
if (target.name === '') {
name = 'security.xframe.value.nested';
value = target.value;
}
}
this.props.changeInput(name, value);
2017-07-18 17:52:39 +02:00
}
handleCancel = () => {
this.props.cancelChanges();
}
2017-08-02 15:52:44 +02:00
handleSubmit = (e) => {
e.preventDefault();
2017-07-24 11:11:28 +02:00
const apiUrl = this.props.params.env ? `${this.props.params.slug}/${this.props.params.env}` : this.props.params.slug;
// send only updated settings
2017-08-03 20:10:35 +02:00
const body = this.sendUpdatedParams();
if (!isEmpty(body)) {
this.props.editSettings(body, apiUrl);
} else {
window.Strapi.notification.error('Settings are equals');
}
}
2017-08-03 20:10:35 +02:00
handleSubmitEditDatabase = (databaseName) => {
const body = this.sendUpdatedParams();
const apiUrl = `${databaseName}/${this.props.params.env}`;
2017-08-03 20:10:35 +02:00
if (!isEmpty(body)) {
this.props.databaseEdit(body, apiUrl);
} else {
window.Strapi.notification.error('Settings are equals');
}
}
2017-08-03 20:10:35 +02:00
sendUpdatedParams = () => {
const prevSettings = this.props.home.initialData;
const body = {};
forEach(this.props.home.modifiedData, (value, key) => {
2017-08-04 17:47:38 +02:00
if (value !== prevSettings[key] && key !== 'security.xframe.value.nested') {
body[key] = value;
}
});
2017-08-07 12:50:32 +02:00
if (has(this.props.home.modifiedData, 'security.xframe.value.nested') && this.props.home.modifiedData['security.xframe.value'] === 'ALLOW-FROM') {
2017-08-04 17:47:38 +02:00
const value = includes(this.props.home.modifiedData['security.xframe.value.nested'], 'ALLOW-FROM') ?
`ALLOW-FROM ${this.props.home.modifiedData['security.xframe.value.nested']}`
: `ALLOW-FROM.ALLOW-FROM ${this.props.home.modifiedData['security.xframe.value.nested']}`;
body['security.xframe.value'] = value;
}
2017-08-03 20:10:35 +02:00
return body;
}
2017-08-03 20:10:35 +02:00
handleLanguageDelete = ({ target }) => {
// retrieve the language to delete using the target id
this.props.languageDelete(target.id);
}
2017-08-07 14:03:22 +02:00
handleDatabaseDelete = (dbName) => {
window.Strapi.notification.info('Deleting database');
this.props.databaseDelete(dbName, this.props.params.env);
2017-08-03 20:10:35 +02:00
}
// custom Row rendering for the component List with params slug === languages
2017-07-27 16:07:09 +02:00
renderRowLanguage = (props, key, liStyles) => {
2017-07-25 17:03:47 +02:00
// assign the target id the language name to prepare for delete
const deleteIcon = props.active ? '' : <i className="fa fa-trash" onClick={this.handleLanguageDelete} id={props.name} />; // eslint-disable-line jsx-a11y/no-static-element-interactions
// format the locale to
const defaultLanguageArray = this.formatLanguageLocale(props.name);
// retrieve language name from i18n translation
const languageObject = find(get(this.props.home.listLanguages, ['sections', '0', 'items', '0', 'items']), ['value', join(defaultLanguageArray, '_')]);
// apply i18n
const languageDisplay = isObject(languageObject) ? <FormattedMessage {...{ id: languageObject.name }} /> : '';
2017-07-20 18:27:38 +02:00
const languageLabel = props.active ?
2017-07-27 16:07:09 +02:00
<span className={liStyles.italicText}>
2017-07-20 18:27:38 +02:00
<FormattedMessage {...{id: 'list.languages.default.languages'}} />
</span> :
// set the span's id with the language name to retrieve it
<FormattedMessage {...{id: 'list.languages.set.languages'}}>
{(message) => (
2017-07-27 16:07:09 +02:00
<button className={liStyles.normal} onClick={this.changeDefaultLanguage} id={props.name}>
{message}
2017-07-24 22:35:30 +02:00
</button>
)}
</FormattedMessage>;
2017-07-20 18:27:38 +02:00
2017-08-07 12:50:32 +02:00
const flagName = this.formatLanguageLocale(props.name);
let flag;
switch (flagName.length) {
case 2:
flag = toLower(flagName[1]);
break;
case 3:
flag = toLower(flagName[2]);
break;
default:
flag = toLower(flagName[0]);
}
return (
2017-07-27 16:07:09 +02:00
<li key={key}>
<div className={liStyles.flexLi}>
<div className={liStyles.flexed}>
2017-08-07 12:50:32 +02:00
<div><span className={`flag-icon flag-icon-${flag}`} /></div>
<div className={`${liStyles.label} ${liStyles.capitalized}`}>{languageDisplay}</div>
2017-07-27 16:07:09 +02:00
</div>
<div>{props.name}</div>
<div className={liStyles.centered}>{languageLabel}</div>
<div>{deleteIcon}</div>
</div>
</li>
)
}
renderListTitle = () => {
const availableContentNumber = this.props.home.configsDisplay.sections.length;
const title = availableContentNumber > 1 ? `list.${this.props.params.slug}.title.plural` : `list.${this.props.params.slug}.title.singular`;
const titleDisplay = title ? <FormattedMessage {...{id: title}} /> : '';
return <span>{availableContentNumber}&nbsp;{titleDisplay}</span>
}
renderListButtonLabel = () => `list.${this.props.params.slug}.button.label`;
renderPopUpFormDatabase = (section, props, popUpStyles) => (
map(section.items, (item, key) => {
const isActive = props.values[this.props.home.dbNameTarget] === this.props.home.modifiedData['database.defaultConnection'] ?
<div className={popUpStyles.rounded}><i className="fa fa-check" /></div> : '';
if (item.name === 'form.database.item.default') {
return (
<div
key={key}
className={popUpStyles.defaultConnection}
id={item.target}
onClick={this.setDefaultConnectionDb}
>
{item.name}{isActive}
</div>
);
}
return (
props.renderInput(item, key)
);
})
)
renderPopUpFormLanguage = (section, props) => (
map(section.items, (item, key) => (
<div key={key}>
2017-08-07 12:50:32 +02:00
{props.renderInput(item, key, this.renderCustomLanguagesSelectOption)}
</div>
))
)
2017-08-07 12:50:32 +02:00
renderRowDatabase = (props, key) => (
// const isDefaultConnection = this.props.home.modifiedData['database.defaultConnection'] === props.host;
<RowDatabase
key={key}
data={props}
getDatabase={this.getDatabase}
handleDatabaseDelete={this.handleDatabaseDelete}
sections={this.props.home.specificDatabase.sections}
values={this.props.home.modifiedData}
handleChange={this.handleChange}
renderPopUpForm={this.renderPopUpFormDatabase}
handleSubmit={this.handleSubmitEditDatabase}
/>
2017-08-03 15:01:56 +02:00
)
2017-07-28 15:01:51 +02:00
2017-07-19 13:10:53 +02:00
renderComponent = () => {
// check if settingName (params.slug) has a custom view display
2017-07-24 19:09:56 +02:00
const specificComponent = findKey(this.customComponents, (value) => includes(value, this.props.params.slug)) || 'defaultComponent';
2017-07-19 13:10:53 +02:00
// if custom view display render specificComponent
const Component = this.components[specificComponent];
2017-07-28 15:01:51 +02:00
2017-08-01 15:10:15 +02:00
const listTitle = this.props.params.slug === 'languages' || 'databases' ? this.renderListTitle() : '';
const listButtonLabel = this.props.params.slug === 'languages' || 'databases' ? this.renderListButtonLabel() : '';
// check if HeaderNav component needs to render a form or a list
const renderListComponent = this.props.params.slug === 'databases';
let handleListPopUpSubmit;
// sections is the props used by EditForm in case of list of table rendering we need to change its value
let sections;
let renderPopUpForm = false;
let renderRow = false;
2017-08-01 15:10:15 +02:00
switch (this.props.params.slug) {
case 'languages':
sections = this.props.home.listLanguages.sections;
// custom rendering for PopUpForm
renderPopUpForm = this.renderPopUpFormLanguage;
renderRow = this.renderRowLanguage;
handleListPopUpSubmit = this.props.newLanguagePost;
break;
case 'databases':
sections = this.props.home.addDatabaseSection.sections;
2017-08-03 17:13:25 +02:00
renderPopUpForm = this.renderPopUpFormDatabase;
handleListPopUpSubmit = this.addConnection;
renderRow = this.renderRowDatabase;
break;
default:
sections = this.props.home.configsDisplay.sections;
}
// custom selectOptions for languages
const selectOptions = this.props.params.slug === 'languages' ? this.props.home.listLanguages : [];
2017-07-19 13:10:53 +02:00
return (
<Component
sections={sections}
listItems={this.props.home.configsDisplay.sections}
2017-07-19 13:10:53 +02:00
values={this.props.home.modifiedData}
handleChange={this.handleChange}
handleCancel={this.handleCancel}
handleSubmit={this.handleSubmit}
links={this.props.environments}
path={this.props.location.pathname}
slug={this.props.params.slug}
renderRow={renderRow}
listTitle={listTitle}
listButtonLabel={listButtonLabel}
handlei18n
handleListPopUpSubmit={handleListPopUpSubmit}
selectOptions={selectOptions}
renderPopUpForm={renderPopUpForm}
renderListComponent={renderListComponent}
cancelAction={this.props.home.cancelAction}
2017-07-19 13:10:53 +02:00
/>
);
}
getDatabase = (databaseName) => {
// allow state here just for modal purpose
this.props.specificDatabaseFetch(databaseName, this.props.params.env);
// this.setState({ modal: !this.state.modal });
}
2017-08-03 15:01:56 +02:00
setDefaultConnectionDb = (e) => {
const value = this.state.toggleDefaultConnection ?
this.props.home.addDatabaseSection.sections[1].items[0].value
: this.props.home.modifiedData[this.props.home.dbNameTarget];
// const target = { name: e.target.id, value: this.props.home.modifiedData[this.props.home.dbNameTarget] }
const target = { name: e.target.id, value };
2017-08-03 15:01:56 +02:00
this.handleChange({target});
this.setState({ toggleDefaultConnection: !this.state.toggleDefaultConnection });
2017-08-03 15:01:56 +02:00
}
// Hide database modal
toggle = () => {
this.setState({ modal: !this.state.modal });
}
render() {
2017-07-17 19:19:54 +02:00
if (this.props.home.loading) {
return <div />;
}
return (
2017-07-18 14:07:48 +02:00
<div className={`${styles.home} col-md-9`}>
2017-07-06 16:18:43 +02:00
<Helmet
title="Settings Manager"
2017-07-06 16:18:43 +02:00
meta={[
{ name: 'Settings Manager Plugin', content: 'Modify your app settings' },
2017-07-06 16:18:43 +02:00
]}
/>
2017-07-18 14:07:48 +02:00
<ContentHeader
name={this.props.home.configsDisplay.name}
description={this.props.home.configsDisplay.description}
/>
2017-08-07 12:50:32 +02:00
{this.renderComponent()}
</div>
);
}
}
2017-07-18 12:39:03 +02:00
2017-07-17 18:40:11 +02:00
const mapStateToProps = createStructuredSelector({
2017-07-19 13:10:53 +02:00
environments: makeSelectEnvironments(),
2017-07-17 18:40:11 +02:00
home: selectHome(),
2017-07-19 13:10:53 +02:00
menuSections: makeSelectSections(),
2017-07-17 18:40:11 +02:00
})
function mapDispatchToProps(dispatch) {
2017-07-13 16:55:59 +02:00
return bindActionCreators(
{
cancelChanges,
changeDefaultLanguage,
changeInput,
2017-07-13 16:55:59 +02:00
configFetch,
2017-08-03 17:31:13 +02:00
databaseDelete,
2017-08-03 20:10:35 +02:00
databaseEdit,
2017-08-01 15:10:15 +02:00
databasesFetch,
2017-07-25 17:03:47 +02:00
editSettings,
languageDelete,
languagesFetch,
2017-08-03 17:13:25 +02:00
newDatabasePost,
2017-07-25 17:03:47 +02:00
newLanguagePost,
specificDatabaseFetch,
2017-07-13 16:55:59 +02:00
},
dispatch
)
}
Home.propTypes = {
cancelChanges: React.PropTypes.func,
changeDefaultLanguage: React.PropTypes.func,
changeInput: React.PropTypes.func,
configFetch: React.PropTypes.func.isRequired,
2017-08-03 17:31:13 +02:00
databaseDelete: React.PropTypes.func,
2017-08-03 20:10:35 +02:00
databaseEdit: React.PropTypes.func,
2017-08-01 15:10:15 +02:00
databasesFetch: React.PropTypes.func,
2017-07-24 11:11:28 +02:00
editSettings: React.PropTypes.func,
2017-07-19 13:10:53 +02:00
environments: React.PropTypes.array,
2017-07-18 18:06:15 +02:00
home: React.PropTypes.object,
2017-07-25 17:03:47 +02:00
languageDelete: React.PropTypes.func,
languagesFetch: React.PropTypes.func,
location: React.PropTypes.object,
2017-07-19 13:10:53 +02:00
menuSections: React.PropTypes.array,
2017-08-03 17:13:25 +02:00
newDatabasePost: React.PropTypes.func,
2017-07-25 17:03:47 +02:00
newLanguagePost: React.PropTypes.func,
params: React.PropTypes.object.isRequired,
specificDatabaseFetch: React.PropTypes.func,
};
export default connect(mapStateToProps, mapDispatchToProps)(Home);