Merged in os-152-add-advanced-settings (pull request #130)

Os 152 add advanced settings
This commit is contained in:
Ivan Diaz 2017-02-05 05:46:18 +00:00
commit b2ad2c10ef
11 changed files with 565 additions and 57 deletions

View File

@ -2,21 +2,31 @@ import React from 'react';
import i18n from 'lib-app/i18n';
import Button from 'core-components/button';
import Input from 'core-components/input';
import ModalContainer from 'app-components/modal-container';
class AreYouSure extends React.Component {
static propTypes = {
description: React.PropTypes.node,
onYes: React.PropTypes.func
onYes: React.PropTypes.func,
type: React.PropTypes.oneOf(['default', 'secure'])
};
static defaultProps = {
type: 'default'
};
static contextTypes = {
closeModal: React.PropTypes.func
};
static openModal(description, onYes) {
state = {
password: ''
};
static openModal(description, onYes, type) {
ModalContainer.openModal(
<AreYouSure description={description} onYes={onYes} />
<AreYouSure description={description} onYes={onYes} type={type}/>
);
}
@ -31,8 +41,9 @@ class AreYouSure extends React.Component {
{i18n('ARE_YOU_SURE')}
</div>
<div className="are-you-sure__description" id="are-you-sure__description">
{this.props.description}
{this.props.description || (this.props.type === 'secure' && i18n('PLEASE_CONFIRM_PASSWORD'))}
</div>
{(this.props.type === 'secure') ? this.renderPassword() : null}
<div className="are-you-sure__buttons">
<div className="are-you-sure__yes-button">
<Button type="secondary" size="small" onClick={this.onYes.bind(this)} ref="yesButton" tabIndex="2">
@ -40,7 +51,7 @@ class AreYouSure extends React.Component {
</Button>
</div>
<div className="are-you-sure__no-button">
<Button type="link" size="auto" onClick={this.onNo.bind(this)} tabIndex="2">
<Button type="link" size="auto" onClick={this.onNo.bind(this)} tabIndex="2">
{i18n('CANCEL')}
</Button>
</div>
@ -49,11 +60,31 @@ class AreYouSure extends React.Component {
);
}
onYes() {
this.closeModal();
renderPassword() {
return (
<Input className="are-you-sure__password" password placeholder="password" name="password" value={this.state.password} onChange={this.onPasswordChange.bind(this)} onKeyDown={this.onInputKeyDown.bind(this)}/>
);
}
if (this.props.onYes) {
this.props.onYes();
onPasswordChange(event) {
this.setState({
password: event.target.value
});
}
onInputKeyDown(event) {
if (event.keyCode == 13) {
this.onYes();
}
}
onYes() {
if (this.props.type === 'default' || this.state.password){
this.closeModal();
if (this.props.onYes) {
this.props.onYes(this.state.password);
}
}
}

View File

@ -27,4 +27,10 @@
display: inline-block;
margin-right: 10px;
}
&__password {
margin: 0 auto;
margin-top: -30px;
margin-bottom: 20px;
}
}

View File

@ -1,5 +1,6 @@
import React from 'react';
import classNames from 'classnames';
import i18n from 'lib-app/i18n';
class ToggleButton extends React.Component {
@ -12,12 +13,22 @@ class ToggleButton extends React.Component {
render() {
return (
<div className="toggle-button" onClick={this.onClick.bind(this)}>
<div className={this.getClass()} onClick={this.onClick.bind(this)}>
{this.props.value ? i18n('ON') : i18n('OFF')}
</div>
);
}
getClass() {
let classes = {
'toggle-button': true,
[this.props.className]: (this.props.className)
};
return classNames(classes);
}
onClick() {
if (this.props.onChange) {
this.props.onChange({

View File

@ -50,9 +50,8 @@ import AdminPanelDepartments from 'app/admin/panel/staff/admin-panel-departments
import AdminPanelViewStaff from 'app/admin/panel/staff/admin-panel-view-staff';
import AdminPanelSystemPreferences from 'app/admin/panel/settings/admin-panel-system-preferences';
import AdminPanelUserSystem from 'app/admin/panel/settings/admin-panel-user-system';
import AdminPanelAdvancedSettings from 'app/admin/panel/settings/admin-panel-advanced-settings';
import AdminPanelEmailTemplates from 'app/admin/panel/settings/admin-panel-email-templates';
import AdminPanelCustomFields from 'app/admin/panel/settings/admin-panel-custom-fields';
const history = syncHistoryWithStore(browserHistory, store);
@ -123,9 +122,8 @@ export default (
<Route path="settings">
<IndexRedirect to="system-preferences" />
<Route path="system-preferences" component={AdminPanelSystemPreferences} />
<Route path="user-system" component={AdminPanelUserSystem} />
<Route path="advanced-settings" component={AdminPanelAdvancedSettings} />
<Route path="email-templates" component={AdminPanelEmailTemplates} />
<Route path="custom-fields" component={AdminPanelCustomFields} />
</Route>
</Route>
</Route>

View File

@ -201,19 +201,14 @@ class AdminPanelMenu extends React.Component {
level: 3
},
{
name: i18n('USER_SYSTEM'),
path: '/admin/panel/settings/user-system',
name: i18n('ADVANCED_SETTINGS'),
path: '/admin/panel/settings/advanced-settings',
level: 3
},
{
name: i18n('EMAIL_TEMPLATES'),
path: '/admin/panel/settings/email-templates',
level: 3
},
{
name: i18n('FILTERS_CUSTOM_FIELDS'),
path: '/admin/panel/settings/custom-fields',
level: 3
}
])
}

View File

@ -0,0 +1,288 @@
import React from 'react';
import {connect} from 'react-redux';
import ConfigActions from 'actions/config-actions';
import API from 'lib-app/api-call';
import i18n from 'lib-app/i18n';
import ToggleButton from 'app-components/toggle-button';
import AreYouSure from 'app-components/are-you-sure';
import ModalContainer from 'app-components/modal-container';
import Message from 'core-components/message';
import Button from 'core-components/button';
import FileUploader from 'core-components/file-uploader';
import Header from 'core-components/header';
import Listing from 'core-components/listing';
import Form from 'core-components/form';
import FormField from 'core-components/form-field';
import SubmitButton from 'core-components/submit-button';
class AdminPanelAdvancedSettings extends React.Component {
state = {
loading: true,
messageType: '',
messageContent: '',
keyName: '',
keyCode: '',
selectedAPIKey: -1,
APIKeys: []
};
componentDidMount() {
this.getAllKeys();
}
render() {
return (
<div className="admin-panel-advanced-settings">
<Header title={i18n('ADVANCED_SETTINGS')} description={i18n('ADVANCED_SETTINGS_DESCRIPTION')}/>
{(this.state.messageType) ? this.renderMessage() : null}
<div className="row">
<div className="col-md-12">
<div className="col-md-6">
<div className="admin-panel-advanced-settings__user-system-enabled">
<span className="admin-panel-advanced-settings__text">{i18n('ENABLE_USER_SYSTEM')}</span>
<ToggleButton className="admin-panel-advanced-settings__toggle-button" value={this.props.config['user-system-enabled']} onChange={this.onToggleButtonUserSystemChange.bind(this)}/>
</div>
</div>
<div className="col-md-6">
<div className="admin-panel-advanced-settings__registration">
<span className="admin-panel-advanced-settings__text">{i18n('ENABLE_USER_REGISTRATION')}</span>
<ToggleButton className="admin-panel-advanced-settings__toggle-button" value={this.props.config['registration']} onChange={this.onToggleButtonRegistrationChange.bind(this)}/>
</div>
</div>
</div>
<div className="col-md-12">
<span className="separator" />
</div>
<div className="col-md-12">
<div className="col-md-3">
<div className="admin-panel-advanced-settings__text">{i18n('INCLUDE_USERS_VIA_CSV')}</div>
<FileUploader className="admin-panel-advanced-settings__button" text="Upload" onChange={this.onImportCSV.bind(this)}/>
</div>
<div className="col-md-3">
<div className="admin-panel-advanced-settings__text">{i18n('INCLUDE_DATABASE_VIA_SQL')}</div>
<FileUploader className="admin-panel-advanced-settings__button" text="Upload" onChange={this.onImportSQL.bind(this)}/>
</div>
<div className="col-md-3">
<div className="admin-panel-advanced-settings__text">{i18n('BACKUP_DATABASE')}</div>
<Button className="admin-panel-advanced-settings__button" type="secondary" size="medium" onClick={this.onBackupDatabase.bind(this)}>Download</Button>
</div>
<div className="col-md-3">
<div className="admin-panel-advanced-settings__text">{i18n('DELETE_ALL_USERS')}</div>
<Button className="admin-panel-advanced-settings__button" size="medium" onClick={this.onDeleteAllUsers.bind(this)}>Delete</Button>
</div>
</div>
<div className="col-md-12">
<span className="separator" />
</div>
<div className="col-md-12 admin-panel-advanced-settings__api-keys">
<div className="col-md-12 admin-panel-advanced-settings__api-keys-title">{i18n('REGISTRATION_API_KEYS')}</div>
<div className="col-md-4">
<Listing {...this.getListingProps()} />
</div>
<div className="col-md-8">
{(this.state.selectedAPIKey === -1) ? this.renderNoKey() : this.renderKey()}
</div>
</div>
</div>
</div>
);
}
renderMessage() {
return (
<Message type={this.state.messageType}>{this.state.messageContent}</Message>
);
}
renderNoKey() {
return (
<div className="admin-panel-advanced-settings__api-keys-none">
{i18n('NO_KEY_SELECTED')}
</div>
);
}
renderKey() {
let currentAPIKey = this.state.APIKeys[this.state.selectedAPIKey];
return (
<div className="admin-panel-advanced-settings__api-keys-info">
<div className="admin-panel-advanced-settings__api-keys-subtitle">{i18n('NAME_OF_KEY')}</div>
<div className="admin-panel-advanced-settings__api-keys-data">{currentAPIKey.name}</div>
<div className="admin-panel-advanced-settings__api-keys-subtitle">{i18n('KEY')}</div>
<div className="admin-panel-advanced-settings__api-keys-data">{currentAPIKey.token}</div>
<Button className="admin-panel-advanced-settings__api-keys-button" size="medium" onClick={this.onDeleteKeyClick.bind(this)}>
{i18n('DELETE')}
</Button>
</div>
);
}
getListingProps() {
return {
title: i18n('REGISTRATION_API_KEYS'),
enableAddNew: true,
items: this.state.APIKeys.map((item) => {
return {
content: item.name,
icon: ''
};
}),
selectedIndex: this.state.selectedAPIKey,
onChange: index => this.setState({selectedAPIKey: index}),
onAddClick: this.openAPIKeyModal.bind(this)
};
}
openAPIKeyModal() {
ModalContainer.openModal(
<Form className="admin-panel-advanced-settings__api-keys-modal" onSubmit={this.addAPIKey.bind(this)}>
<Header title={i18n('ADD_API_KEY')} description={i18n('ADD_API_KEY_DESCRIPTION')}/>
<FormField name="name" label={i18n('NAME_OF_KEY')} validation="DEFAULT" required fieldProps={{size: 'large'}}/>
<SubmitButton type="secondary">{i18n('SUBMIT')}</SubmitButton>
</Form>
);
}
addAPIKey({name}) {
ModalContainer.closeModal();
API.call({
path: '/system/add-api-key',
data: {name}
}).then(this.getAllKeys.bind(this));
}
getAllKeys() {
API.call({
path: '/system/get-api-keys',
data: {}
}).then(this.onRetrieveSuccess.bind(this));
}
onDeleteKeyClick() {
AreYouSure.openModal(null, () => {
API.call({
path: '/system/delete-api-key',
data: {
name: this.state.APIKeys[this.state.selectedAPIKey].name
}
}).then(this.getAllKeys.bind(this));
});
}
onRetrieveSuccess(result) {
this.setState({
APIKeys: result.data,
selectedAPIKey: -1
});
}
onToggleButtonUserSystemChange() {
AreYouSure.openModal(null, this.onAreYouSureUserSystemOk.bind(this), 'secure');
}
onToggleButtonRegistrationChange() {
AreYouSure.openModal(null, this.onAreYouSureRegistrationOk.bind(this), 'secure');
}
onAreYouSureUserSystemOk(password) {
API.call({
path: this.props.config['user-system-enabled'] ? '/system/disable-user-system' : '/system/enable-user-system',
data: {
password: password
}
}).then(() => {
this.setState({
messageType: 'success',
messageContent: this.props.config['user-system-enabled'] ? i18n('USER_SYSTEM_DISABLED') : i18n('USER_SYSTEM_ENABLED')
});
this.props.dispatch(ConfigActions.updateData());
}).catch(() => this.setState({messageType: 'error', messageContent: i18n('ERROR_UPDATING_SETTINGS')}));
}
onAreYouSureRegistrationOk(password) {
API.call({
path: this.props.config['registration'] ? '/system/disable-registration' : '/system/enable-registration',
data: {
password: password
}
}).then(() => {
this.setState({
messageType: 'success',
messageContent: this.props.config['registration'] ? i18n('REGISTRATION_DISABLED') : i18n('REGISTRATION_ENABLED')
});
this.props.dispatch(ConfigActions.updateData());
}).catch(() => this.setState({messageType: 'error', messageContent: i18n('ERROR_UPDATING_SETTINGS')}));
}
onImportCSV(event) {
AreYouSure.openModal(null, this.onAreYouSureCSVOk.bind(this, event.target.value), 'secure');
}
onImportSQL(event) {
AreYouSure.openModal(null, this.onAreYouSureSQLOk.bind(this, event.target.value), 'secure');
}
onAreYouSureCSVOk(file, password) {
API.call({
path: '/system/import-csv',
data: {
file: file,
password: password
}
})
.then(() => this.setState({messageType: 'success', messageContent: i18n('SUCCESS_IMPORTING_CSV_DESCRIPTION')}))
.catch(() => this.setState({messageType: 'error', messageContent: i18n('ERROR_IMPORTING_CSV_DESCRIPTION')}));
}
onAreYouSureSQLOk(file, password) {
API.call({
path: '/system/import-sql',
data: {
file: file,
password: password
}
})
.then(() => this.setState({messageType: 'success', messageContent: i18n('SUCCESS_IMPORTING_SQL_DESCRIPTION')}))
.catch(() => this.setState({messageType: 'error', messageContent: i18n('ERROR_IMPORTING_SQL_DESCRIPTION')}));
}
onBackupDatabase() {
API.call({
path: '/system/backup-database',
plain: true,
data: {}
}).then((result) => {
let contentType = 'application/octet-stream';
let link = document.createElement('a');
let blob = new Blob([result], {'type': contentType});
link.href = window.URL.createObjectURL(blob);
link.download = 'backup.sql';
link.click();
});
}
onDeleteAllUsers() {
AreYouSure.openModal(null, this.onAreYouSureDeleteAllUsersOk.bind(this), 'secure');
}
onAreYouSureDeleteAllUsersOk(password) {
API.call({
path: '/system/delete-all-users',
data: {
password: password
}
}).then(() => this.setState({messageType: 'success', messageContent: i18n('SUCCESS_DELETING_ALL_USERS')}
)).catch(() => this.setState({messageType: 'error', messageContent: i18n('ERROR_DELETING_ALL_USERS')}));
}
}
export default connect((store) => {
return {
config: store.config
};
})(AdminPanelAdvancedSettings);

View File

@ -0,0 +1,64 @@
@import "../../../../scss/vars";
.admin-panel-advanced-settings {
&__user-system-enabled {
}
&__registration {
}
&__toggle-button {
display: inline-block;
margin-left: 20px;
margin-top: 20px;
margin-bottom: 20px;
}
&__text {
margin-top: 30px;
margin-bottom: 20px;
}
&__button {
margin-bottom: 30px;
width: 150px;
}
&__api-keys {
&-title {
font-size: $font-size--bg;
margin-bottom: 20px;
text-align: left;
}
&-info {
text-align: left;
}
&-subtitle {
font-size: $font-size--md;
margin-bottom: 5px;
}
&-data {
background-color: $light-grey;
border-radius: 4px;
width: 300px;
margin: 10px 0;
text-align: center;
padding: 5px 0;
}
&-modal {
min-width: 500px;
}
&-none {
color: $dark-grey;
font-size: $font-size--md;
}
}
}

View File

@ -1,14 +0,0 @@
import React from 'react';
class AdminPanelCustomFields extends React.Component {
render() {
return (
<div>
/admin/panel/settings/custom-fields
</div>
);
}
}
export default AdminPanelCustomFields;

View File

@ -1,14 +0,0 @@
import React from 'react';
class AdminPanelUserSystem extends React.Component {
render() {
return (
<div>
/admin/panel/settings/user-system
</div>
);
}
}
export default AdminPanelUserSystem;

View File

@ -1,7 +1,7 @@
module.exports = [
{
path: '/system/get-settings',
time: 1000,
time: 850,
response: function (params) {
if(params && params.allSettings) {
return {
@ -29,7 +29,9 @@ module.exports = [
{id: 3, name: 'System and Administration', owners: 0}
],
'allowedLanguages': ['en', 'es', 'de', 'fr', 'pt', 'jp', 'ru', 'cn', 'in', 'tr'],
'supportedLanguages': ['en', 'es', 'de']
'supportedLanguages': ['en', 'es', 'de'],
'registration': true,
'user-system-enabled': true
}
};
@ -50,7 +52,9 @@ module.exports = [
{id: 3, name: 'System and Administration', owners: 0}
],
'allowedLanguages': ['en', 'es', 'de', 'fr', 'pt', 'jp', 'ru', 'cn', 'in', 'tr'],
'supportedLanguages': ['en', 'es', 'de']
'supportedLanguages': ['en', 'es', 'de'],
'registration': true,
'user-system-enabled': true
}
};
}
@ -124,6 +128,44 @@ module.exports = [
return 'text content';
}
},
{
path: '/system/delete-all-users',
time: 100,
response: function () {
return {
status: 'success',
data: {}
};
}
},
{
path: '/system/backup-database',
time: 100,
contentType: 'application/octet-stream',
response: function () {
return 'text content';
}
},
{
path: '/system/import-csv',
time: 100,
response: function () {
return {
status: 'success',
data: {}
};
}
},
{
path: '/system/import-sql',
time: 100,
response: function () {
return {
status: 'success',
data: {}
};
}
},
{
path: '/system/get-mail-templates',
time: 100,
@ -236,13 +278,96 @@ module.exports = [
};
}
},
{
path: '/system/enable-user-system',
time: 100,
response: function () {
return {
status: 'success',
data: {}
}
}
},
{
path: '/system/disable-user-system',
time: 100,
response: function () {
return {
status: 'success',
data: {}
}
}
},
{
path: '/system/enable-registration',
time: 100,
response: function () {
return {
status: 'success',
data: {}
}
}
},
{
path: '/system/disable-registration',
time: 100,
response: function () {
return {
status: 'success',
data: {}
}
}
},
{
path: '/system/add-api-key',
time: 300,
response: function () {
return {
status: 'success',
data: {}
};
}
},
{
path: '/system/delete-api-key',
time: 300,
response: function () {
return {
status: 'success',
data: {}
};
}
},
{
path: '/system/get-api-keys',
time: 300,
response: function () {
return {
status: 'success',
data: [
{
name: 'Game System Registration',
token: '9as8da9s51c6a51c51a9s1c9asdf1'
},
{
name: 'PHPbb forum',
token: 'apires1qe65fq65e1f6a5e1f6afaef2'
},
{
name: 'How do you turn this on?',
token: 'das65d4as651age16wq6ofqwwcemcw'
}
]
}
}
},
{
path: '/system/get-logs',
time: 300,
response: function() {
response: function () {
return {
"status": "success",
"data": [
status: "success",
data: [
{
"type": "EDIT_SETTINGS",
"to": null,

View File

@ -48,7 +48,7 @@ export default {
'STAFF_MEMBERS': 'Staff Members',
'DEPARTMENTS': 'Departments',
'SYSTEM_PREFERENCES': 'System Preferences',
'USER_SYSTEM': 'User System',
'ADVANCED_SETTINGS': 'Advanced Settings',
'EMAIL_TEMPLATES': 'Email Templates',
'FILTERS_CUSTOM_FIELDS': 'Filters and Custom Fields',
'PRIORITY': 'Priority',
@ -153,6 +153,18 @@ export default {
'ALL_NOTIFICATIONS': 'All notifications',
'VERIFY_SUCCESS': 'User verified',
'VERIFY_FAILED': 'Could not verify',
'ENABLE_USER_SYSTEM': 'Use user system for customers',
'ENABLE_USER_REGISTRATION': 'Enable user registration',
'INCLUDE_USERS_VIA_CSV': 'Include users via CSV file',
'INCLUDE_DATABASE_VIA_SQL': 'Include database via SQL file',
'BACKUP_DATABASE': 'Backup database',
'DELETE_ALL_USERS': 'Delete all users',
'PLEASE_CONFIRM_PASSWORD': 'Please confirm your password to make these changes',
'REGISTRATION_API_KEYS': 'Registration API keys',
'NAME_OF_KEY': 'Name of key',
'KEY': 'Key',
'ADD_API_KEY': 'Add API Key',
'NO_KEY_SELECTED': 'No Key selected',
'CHECK_TICKET': 'Check Ticket',
'ACTIVITY': 'Activity',
'HOME': 'Home',
@ -225,6 +237,12 @@ export default {
'VERIFY_SUCCESS_DESCRIPTION': 'You user has been verified correctly. You can log in now.',
'VERIFY_FAILED_DESCRIPTION': 'The verification could not be done.',
'STATISTICS_DESCRIPTION': 'Here you can view statistics related to tickets and signups.',
'ADVANCED_SETTINGS_DESCRIPTION': 'Here you can change the advanced settings of your system. Please be careful, the changes you make can not be reversed.',
'USER_SYSTEM_DISABLED': 'User system has been disabled',
'USER_SYSTEM_ENABLED': 'User system has been enabled',
'REGISTRATION_DISABLED': 'Registration has been disabled',
'REGISTRATION_ENABLED': 'Registration has been enabled',
'ADD_API_KEY_DESCRIPTION': 'Insert the name and a registration api key be generated.',
//ERRORS
'EMAIL_OR_PASSWORD': 'Email or password invalid',