Commit 91a2ec23 authored by Patricio Bruna's avatar Patricio Bruna

Merge pull request #42 from ZBoxApp/distribution_lists

apply store in distribution list and mailbox, and add, edit, remove, distribution list, add pagination mailbox
parents 33df3db4 f190b8af
// Copyright (c) 2016 ZBox, Spa. All Rights Reserved.
// See LICENSE.txt for license information.
import $ from 'jquery';
import React from 'react';
import EventStore from '../../stores/event_store.jsx';
import PageInfo from '../page_info.jsx';
import PanelTab from '../panel_tab.jsx';
import Button from '../button.jsx';
import Panel from '../panel.jsx';
import ActionsPanel from '../panel_actions.jsx';
import ActionsPanelAllows from '../panel_actions_allows.jsx';
import MessageBar from '../message_bar.jsx';
import Promise from 'bluebird';
import * as Client from '../../utils/client.jsx';
import * as Utils from '../../utils/utils.jsx';
import * as GlobalActions from '../../action_creators/global_actions.jsx';
import DomainStore from '../../stores/domain_store.jsx';
import Constants from '../../utils/constants.jsx';
const MessagesType = Constants.MessageType;
export default class DistributionLists extends React.Component {
constructor(props) {
super(props);
this.getDistributionLists = this.getDistributionLists.bind(this);
this.showMessage = this.showMessage.bind(this);
this.onDeleteMember = this.onDeleteMember.bind(this);
this.onDeleteOwner = this.onDeleteOwner.bind(this);
this.onSubmitMembers = this.onSubmitMembers.bind(this);
this.onCancelMember = this.onCancelMember.bind(this);
this.onCancelOwner = this.onCancelOwner.bind(this);
this.domain = null;
this.state = {};
}
showMessage(attrs) {
const autoTimer = 10;
this.setState({
error: attrs.error,
type: attrs.typeError,
autocloseInSecs: autoTimer
});
}
getDistributionLists() {
const id = this.props.params.id;
const response = {};
const domain = DomainStore.getCurrent();
return new Promise((resolve, reject) => {
if (domain) {
response.domain = domain;
const dl = DomainStore.getDistributionListById(id, domain);
response.distributionsList = dl;
dl.getOwners((error, owners) => {
if (owners) {
response.owners = owners;
return resolve(response);
}
return reject(error);
});
}
return Client.getDistributionList(id, (success) => {
const distributionsList = success;
response.distributionsList = distributionsList;
const domainId = this.props.params.domain_id;
distributionsList.getOwners((error, owners) => {
if (owners) {
response.owners = owners;
Client.getDomain(domainId, (doma) => {
response.domain = doma;
resolve(response);
}, (err) => {
reject(err);
});
}
});
}, (error) => {
reject(error);
});
}).then((data) => {
DomainStore.setOwners(Utils.getOwners(data.owners));
DomainStore.setMembers(data.distributionsList.members);
this.setState({
distributionsList: data.distributionsList,
members: DomainStore.getMembers(),
owners: DomainStore.getOwners(),
domain: data.domain
});
}).catch((error) => {
GlobalActions.emitMessage({
error: error.message,
typeError: MessagesType.ERROR
});
}).finally(() => {
GlobalActions.emitEndLoading();
});
}
onSubmitOwners(response) {
if (response.refresh) {
response.refresh.forEach((member) => {
DomainStore.addOwners(member);
});
}
this.multipleActionsOwners(response, this.state.distributionsList).then((res) => {
const newOwners = DomainStore.getOwners();
const errors = [];
const limit = res.length;
for (let i = 0; i < limit; i++) {
const items = res[i];
if (items.error) {
const action = (items.action === 'remove') ? 'eliminar' : 'agregar';
errors.push({
error: `Hubo un error al ${action} ${items.item}, debido a : ${items.error.extra.reason}`,
type: MessagesType.ERROR
});
}
}
if (errors.length !== limit) {
errors.push({
error: 'Se han guardado los datos para permitidos éxitosamente.',
type: MessagesType.SUCCESS
});
}
this.setState({
owners: newOwners,
error: errors
});
response.reset();
});
}
onSubmitMembers(response) {
if (response.refresh) {
response.refresh.forEach((member) => {
DomainStore.addMember(member);
});
}
this.multipleActionsMembers(response, this.state.distributionsList).then((res) => {
const newMembers = DomainStore.getMembers();
const errors = [];
const limit = res.length;
for (let i = 0; i < limit; i++) {
const items = res[i];
if (items.error) {
const action = (items.action === 'remove') ? 'eliminar' : 'agregar';
errors.push({
error: `Hubo un error al ${action} ${items.item}, debido a : ${items.error.extra.reason}`,
type: MessagesType.ERROR
});
}
}
if (errors.length !== limit) {
errors.push({
error: 'Se han guardado los datos para miembros éxitosamente.',
type: MessagesType.SUCCESS
});
}
this.setState({
members: newMembers,
error: errors
});
response.reset();
});
}
multipleActionsMembers(response, account) {
const promises = [];
if (response.add || response.remove) {
if (response.add) {
const add = new Promise((resolve) => {
account.addMembers(response.add, (error) => {
const res = {};
if (error) {
res.isCompleted = false;
res.action = 'add';
res.error = error;
return resolve(res);
}
response.add.forEach((member) => {
DomainStore.addMember(member);
});
res.isCompleted = true;
res.action = 'add';
return resolve(res);
});
});
promises.push(add);
}
if (response.remove) {
const remove = new Promise((resolve) => {
account.removeMembers(response.remove, (error) => {
const res = {};
if (error) {
res.isCompleted = false;
res.action = 'remove';
res.error = error;
return resolve(res);
}
response.remove.forEach((member) => {
DomainStore.removeMember(member);
});
res.isCompleted = true;
res.action = 'remove';
return resolve(res);
});
});
promises.push(remove);
}
}
return Promise.all(promises);
}
multipleActionsOwners(response, account) {
const promises = [];
for (const key in response) {
if (response.hasOwnProperty(key) && key === 'add') {
const array = response[key];
const limit = array.length;
for (let index = 0; index < limit; index++) {
const res = {};
const promesa = new Promise((resolve) => {
account.addOwner(array[index], (error) => {
if (error) {
res.isCompleted = false;
res.item = response[key][index];
res.action = key;
res.error = error;
} else {
res.isCompleted = true;
res.item = response[key][index];
res.action = key;
DomainStore.addOwners(response[key][index]);
}
return resolve(res);
});
});
promises.push(promesa);
}
}
if (response.hasOwnProperty(key) && key === 'remove') {
const array = response[key];
const limit = array.length;
for (let index = 0; index < limit; index++) {
const res = {};
const promesa = new Promise((resolve) => {
account.removeOwner(array[index], (error) => {
if (error) {
res.isCompleted = false;
res.item = response[key][index];
res.action = key;
res.error = error;
} else {
res.isCompleted = true;
res.item = response[key][index];
res.action = key;
}
return resolve(res);
});
});
promises.push(promesa);
}
}
}
return Promise.all(promises);
}
onDeleteMember(member) {
DomainStore.removeMember(member);
const currentMembers = DomainStore.getMembers();
this.setState({
members: currentMembers,
error: false
});
}
onCancelMember(response) {
if (response && response.length > 0) {
response.forEach((member) => {
DomainStore.addMember(member);
});
const newMembers = DomainStore.getMembers();
this.setState({
members: newMembers,
error: false
});
}
return null;
}
onDeleteOwner(owner) {
DomainStore.removeOwner(owner);
const currentOwners = DomainStore.getOwners();
this.setState({
owners: currentOwners,
error: false
});
}
onCancelOwner(response) {
if (response && response.length > 0) {
response.forEach((member) => {
DomainStore.addOwners(member);
});
const newOwners = DomainStore.getOwners();
this.setState({
owners: newOwners,
error: false
});
}
return null;
}
componentDidMount() {
EventStore.addMessageListener(this.showMessage);
$('#sidebar-domains').addClass('active');
this.getDistributionLists();
}
componentWillUnmount() {
EventStore.removeMessageListener(this.showMessage);
$('#sidebar-domains').removeClass('active');
}
render() {
let generalData;
let domainInfo;
let btnsGeneralInfo = [];
let actionTabsAllows = [];
let actionTabsMembers = [];
let message;
let panelTabs;
let isPrivate = null;
if (this.state.distributionsList && this.state.owners) {
const data = this.state.distributionsList;
const domain = this.state.domain;
const owners = this.state.owners;
const arrayMembers = this.state.members;
const membersFormatted = Utils.getMembers(data.members, 'Miembros');
if (owners.length > 0) {
isPrivate = (
<span className='label label-danger'>
{'Privada'}
</span>
);
}
generalData = (
<div>
<h4>{data.name}</h4>
<p>{membersFormatted}</p>
{isPrivate}
</div>
);
domainInfo = (
<div>
<h4>
<Button
btnAttrs={
{
className: 'text-success domain-name',
onClick: (e) => {
Utils.handleLink(e, `/domains/${domain.id}`);
}
}
}
>
{`@${domain.name}`}
</Button>
</h4>
</div>
);
btnsGeneralInfo = [
{
props: {
className: 'btn btn-xs btn-default',
onClick: (e) => {
Utils.handleLink(e, `/domains/${this.props.params.domain_id}/distribution_lists/${this.props.params.id}/edit`, this.props.location);
}
},
label: 'Editar'
}
];
actionTabsMembers = (
<ActionsPanel
name={'Miembros'}
data={arrayMembers}
onApplyChanges={(response) => {
this.onSubmitMembers(response);
}}
hasExport={true}
isEmail={true}
onDelete={(member) => {
this.onDeleteMember(member);
}}
onCancel={(response) => {
this.onCancelMember(response);
}}
/>
);
actionTabsAllows = (
<ActionsPanelAllows
name={'Permitidos'}
data={owners}
onApplyChanges={(response) => {
this.onSubmitOwners(response);
}}
hasExport={true}
isEmail={true}
onDelete={(owner) => {
this.onDeleteOwner(owner);
}}
onCancel={(response) => {
this.onCancelOwner(response);
}}
/>
);
}
if (this.state.error) {
if (Array.isArray(this.state.error)) {
message = this.state.error.map((err, i) => {
return (
<MessageBar
key={`new-error-${i}`}
message={err.error}
type={err.type}
autoclose={true}
/>
);
});
} else {
message = (
<MessageBar
message={this.state.error}
type={this.state.type}
autoclose={true}
/>
);
}
}
const pageInfo = (
<PageInfo
titlePage='lista de distribución'
descriptionPage='Para enviar correo a grupos de usuarios'
/>
);
const allows = (
<Panel
title='Permitidos'
hasHeader={false}
classHeader={'reset-panel'}
children={actionTabsAllows}
/>
);
const members = (
<Panel
title='Miembres'
hasHeader={false}
classHeader={'reset-panel'}
children={actionTabsMembers}
/>
);
panelTabs = (
<PanelTab
tabNames={['Miembros', 'Permitidos']}
tabs={{
miembros: members,
permitidos: allows
}}
location={this.props.location}
/>
);
if (this.state.notFound) {
return (
<div>
{pageInfo}
<div className='block-center text-center'>
<h3>{this.state.message}</h3>
</div>
</div>
);
}
return (
<div>
{pageInfo}
<div className='content animate-panel'>
{message}
<div className='row'>
<div className='col-md-6 central-content'>
<Panel
title='Información General'
btnsHeader={btnsGeneralInfo}
children={generalData}
classHeader='with-min-height'
/>
</div>
<div className='col-md-6 central-content'>
<Panel
title='Dominio'
children={domainInfo}
classHeader='with-min-height'
/>
</div>
</div>
<div className='row'>
<div className='col-md-12 panel-with-tabs'>
{panelTabs}
</div>
</div>
</div>
</div>
);
}
}
DistributionLists.propTypes = {
location: React.PropTypes.object,
params: React.PropTypes.object
};
import $ from 'jquery';
import React from 'react';
import Button from '../button.jsx';
import MessageBar from '../message_bar.jsx';
import Panel from '../panel.jsx';
import * as Client from '../../utils/client.jsx';
import * as GlobalActions from '../../action_creators/global_actions.jsx';
import * as Utils from '../../utils/utils.jsx';
import EventStore from '../../stores/event_store.jsx';
import Promise from 'bluebird';
import Constants from '../../utils/constants.jsx';
const messageType = Constants.MessageType;
export default class EditDistributionList extends React.Component {
constructor(props) {
super(props);
this.showMessage = this.showMessage.bind(this);
this.saveChanges = this.saveChanges.bind(this);
this.state = {};
}
showMessage(attrs) {
this.setState({
error: attrs.error,
type: attrs.typeError
});
}
saveChanges(e) {
e.preventDefault();
Utils.toggleStatusButtons('.action-edit-dl', true);
Utils.validateInputRequired(this.refs).then(() => {
const id = this.props.params.id;
const attrs = {};
const mail = this.refs.mail.value;
attrs.displayName = this.refs.displayName.value;
Client.modifyDistributionList(id, attrs, (dl) => {
const domain = dl.name.split('@').pop();
const newNameDL = `${mail}@${domain}`;
dl.rename(newNameDL, (err) => {
Utils.toggleStatusButtons('.action-edit-dl', false);
if (err) {
return GlobalActions.emitMessage({
error: err.extra.reason,
typeError: messageType.ERROR
});
}
return GlobalActions.emitMessage({
error: 'Se han actualizado sus datos éxitosamente.',
typeError: messageType.SUCCESS
});
});
}, (err) => {
GlobalActions.emitMessage({
error: err.message,
typeError: messageType.ERROR
});
Utils.toggleStatusButtons('.action-edit-dl', false);
});
}).catch((error) => {
GlobalActions.emitMessage({
error: error.message,
type: messageType.ERROR
});
error.node.focus();
Utils.toggleStatusButtons('.action-edit-dl', false);
});
}
getDistributionList() {
const id = this.props.params.id;
new Promise((resolve, reject) => {
Client.getDistributionList(id, (success) => {
resolve(success);
}, (error) => {
reject(error);
});
}).then((res) => {
const domain = this.refs.domain;
const displayName = this.refs.displayName;
const mail = this.refs.mail;
const dl = res.name.split('@');
domain.innerHTML = dl.pop();
if (res.attrs.displayName) {
displayName.value = res.attrs.displayName;
}
mail.value = dl.shift();
}).catch((err) => {
GlobalActions.emitMessage({
error: err.message,
type: messageType.ERROR
});
Utils.toggleStatusButtons('.action-edit-dl', true);
}).finally(() => {
GlobalActions.emitEndLoading();
});
}
componentDidMount() {
EventStore.addMessageListener(this.showMessage);
GlobalActions.emitEndLoading();
$('#sidebar-domain').removeClass('active');
this.getDistributionList();
}
componentWillUnmount() {
EventStore.removeMessageListener(this.showMessage);
$('#sidebar-domain').removeClass('active');
}
render() {
let message;
let form;
let actions;
if (this.state.error) {
message = (
<MessageBar
message={this.state.error}
type={this.state.type}
autoclose={true}
/>
);
}
form = (
<form
className='simple_form form-horizontal mailbox-form'
id='editAccount'
>
<div className='form-group string'>
<label className='string required col-sm-3 control-label'>
<abbr title='requerido'>{'*'}</abbr>
{'Dirección'}
</label>
<div className='col-sm-8'>
<div className='input-group'>
<input
type='text'
className='form-control'
ref='mail'
data-required='true'
data-message='La dirección de correo es requerida, por favor verifique.'
placeholder='Dirección'
/>
<span
className='input-group-addon'
ref='domain'
>
</span>
</div>
</div>
</div>
<div className='form-group string'>
<label className='string required col-sm-3 control-label'>
{'Nombre'}
</label>
<div className='col-sm-8'>
<input
type='text'
className='form-control'
ref='displayName'
placeholder='Nombre mostrado en contactos'
/>
</div>
</div>
<div className='form-group'>
<div className='col-sm-3'></div>
<div className='col-sm-8'>
<Button
btnAttrs={
{
className: 'btn btn-info action-edit-dl',
onClick: (e) => {
this.saveChanges(e);
}
}
}
>
{'Guardar'}
</Button>
<Button
btnAttrs={
{
className: 'btn btn-default action-button',
onClick: (e) => {
Utils.handleLink(e, `/domains/${this.props.params.domain_id}/distribution_lists/${this.props.params.id}`);
}
}
}
>
{'Cancelar'}
</Button>
</div>
</div>
</form>
);
actions = [
{
label: 'Guardar',
props: {
className: 'btn btn-info btn-xs action-edit-dl',
onClick: (e) => {
this.saveChanges(e);
}
}
},
{
label: 'Cancelar',
props: {
className: 'btn btn-default btn-xs action-button',
onClick: (e) => {
Utils.handleLink(e, `/domains/${this.props.params.domain_id}/distribution_lists/${this.props.params.id}`);
}
}
}
];
return (
<div>
<div className='content animate-panel'>
{message}
<div className='row'>
<div className='col-md-12 central-content'>
<Panel
title={'Editar Lista de Distribución'}
btnsHeader={actions}
classHeader={'forum-box'}
>
{form}
</Panel>
</div>
</div>
</div>
</div>
);
}
}
EditDistributionList.propTypes = {
location: React.PropTypes.object,
params: React.PropTypes.any
};
...@@ -23,6 +23,7 @@ export default class DomainDistributionList extends React.Component { ...@@ -23,6 +23,7 @@ export default class DomainDistributionList extends React.Component {
} }
getStateFromStores() { getStateFromStores() {
const lists = DomainStore.getDistributionLists(this.props.domain); const lists = DomainStore.getDistributionLists(this.props.domain);
return { return {
lists lists
}; };
...@@ -107,7 +108,7 @@ export default class DomainDistributionList extends React.Component { ...@@ -107,7 +108,7 @@ export default class DomainDistributionList extends React.Component {
<td className='distribution-list-actions'> <td className='distribution-list-actions'>
<a <a
href='#' href='#'
onClick={(e) => Utils.handleLink(e, `/distribution_lists/${dl.id}`)} onClick={(e) => Utils.handleLink(e, `/domains/${domain.id}/distribution_lists/${dl.id}`)}
> >
{'Ver'} {'Ver'}
</a> </a>
......
...@@ -36,7 +36,10 @@ export default class ConfirmDeleteModal extends React.Component { ...@@ -36,7 +36,10 @@ export default class ConfirmDeleteModal extends React.Component {
message: 'Su contraseña se ha sido cambiada éxitosamente.', message: 'Su contraseña se ha sido cambiada éxitosamente.',
typeError: 'text-success' typeError: 'text-success'
}); });
if (this.props.data.name === this.state.currentUser.name) {
this.forceLogout('/logout'); this.forceLogout('/logout');
}
}, (error) => { }, (error) => {
this.setState({ this.setState({
alert: true, alert: true,
......
...@@ -5,6 +5,9 @@ import {browserHistory} from 'react-router'; ...@@ -5,6 +5,9 @@ import {browserHistory} from 'react-router';
import {Modal} from 'react-bootstrap'; import {Modal} from 'react-bootstrap';
import * as Utils from './../../utils/utils.jsx'; import * as Utils from './../../utils/utils.jsx';
import * as Client from './../../utils/client.jsx'; import * as Client from './../../utils/client.jsx';
import Promise from 'bluebird';
import * as GlobalActions from '../../action_creators/global_actions.jsx';
import MailboxStore from '../../stores/mailbox_store.jsx';
import React from 'react'; import React from 'react';
...@@ -30,31 +33,45 @@ export default class ConfirmDeleteModal extends React.Component { ...@@ -30,31 +33,45 @@ export default class ConfirmDeleteModal extends React.Component {
} }
handleDelete() { handleDelete() {
new Promise((resolve, reject) => {
// start loading
GlobalActions.emitStartLoading();
Client.removeAccount( Client.removeAccount(
this.props.data.id, this.props.data.id,
() => { () => {
return resolve(true);
},
(error) => {
return reject(error);
}
);
}).then(() => {
MailboxStore.removeAccount(this.props.data);
this.setState( this.setState(
{ {
alert: true, alert: true,
message: `Su cuenta ${this.props.data.attrs.mail}, ha sido eliminada éxitosamente. Sera redirigido en ${this.state.timeToRedirect} seg`, message: `Su cuenta ${this.props.data.attrs.mail}, ha sido eliminada éxitosamente. Sera redirigido en ${this.state.timeToRedirect} seg`,
typeError: 'text-success' typeError: 'text-warning'
} }
); );
Utils.toggleStatusButtons('.close-modal', true);
this.redirect(); this.redirect();
}, }).catch((error) => {
() => {
this.setState( this.setState(
{ {
alert: true, alert: true,
message: `Hubo un error, al intentar eliminar su cuenta : ${this.props.data.attrs.mail}`, message: error.message,
typeError: 'text-danger' typeError: 'text-edanger'
}
);
} }
); );
}).finally(() => {
GlobalActions.emitEndLoading();
});
} }
redirect() { redirect() {
const redirectAt = 1000;
setTimeout(() => { setTimeout(() => {
if (this.timetoRedict-- < 1) { if (this.timetoRedict-- < 1) {
browserHistory.replace('/mailboxes'); browserHistory.replace('/mailboxes');
...@@ -65,7 +82,7 @@ export default class ConfirmDeleteModal extends React.Component { ...@@ -65,7 +82,7 @@ export default class ConfirmDeleteModal extends React.Component {
this.redirect(); this.redirect();
} }
}, 1000); }, redirectAt);
} }
handleKeyUp() { handleKeyUp() {
...@@ -120,7 +137,7 @@ export default class ConfirmDeleteModal extends React.Component { ...@@ -120,7 +137,7 @@ export default class ConfirmDeleteModal extends React.Component {
<Modal.Footer> <Modal.Footer>
<button <button
type='button' type='button'
className='btn btn-default' className='btn btn-default close-modal'
onClick={this.props.onHide} onClick={this.props.onHide}
> >
{'Cancelar'} {'Cancelar'}
......
...@@ -3,10 +3,14 @@ import React from 'react'; ...@@ -3,10 +3,14 @@ import React from 'react';
import Panel from '../panel.jsx'; import Panel from '../panel.jsx';
import Button from '../button.jsx'; import Button from '../button.jsx';
import MessageBar from '../message_bar.jsx'; import MessageBar from '../message_bar.jsx';
import Promise from 'bluebird';
import DataList from 'react-datalist';
import * as GlobalActions from '../../action_creators/global_actions.jsx'; import * as GlobalActions from '../../action_creators/global_actions.jsx';
import * as Client from '../../utils/client.jsx'; import * as Client from '../../utils/client.jsx';
import * as Utils from '../../utils/utils.jsx'; import * as Utils from '../../utils/utils.jsx';
import EventStore from '../../stores/event_store.jsx';
import MailboxStore from '../../stores/mailbox_store.jsx';
import Constants from '../../utils/constants.jsx'; import Constants from '../../utils/constants.jsx';
...@@ -17,73 +21,168 @@ export default class CreateMailBox extends React.Component { ...@@ -17,73 +21,168 @@ export default class CreateMailBox extends React.Component {
super(props); super(props);
this.handleSubmit = this.handleSubmit.bind(this); this.handleSubmit = this.handleSubmit.bind(this);
this.getAllDomains = this.getAllDomains.bind(this);
this.showMessage = this.showMessage.bind(this);
this.handleRadioChanged = this.handleRadioChanged.bind(this);
this.controllerDataList = this.controllerDataList.bind(this);
this.reset = null;
this.state = {}; this.state = {};
} }
showMessage(attrs) {
this.setState({
error: attrs.message,
typeError: attrs.typeError
});
}
handleSubmit(e) { handleSubmit(e) {
e.preventDefault(); e.preventDefault();
Utils.validateInputRequired(this.refs).then(() => { Utils.validateInputRequired(this.refs).then(() => {
// here assign missing properties. // here assign missing properties.
let attrs = { const domain = document.querySelector('input[list=\'domain\']');
if (domain.value === '') {
GlobalActions.emitMessage({
message: 'El dominio es requerido, verifique por favor.',
typeError: messageType.ERROR
});
domain.focus();
return false;
}
const email = this.refs.mail.value + '@' + domain.value;
//falta campo de tipo de casilla
const attrs = {
givenName: this.refs.givenName.value, givenName: this.refs.givenName.value,
sn: this.refs.sn.value sn: this.refs.sn.value,
description: this.refs.description.value,
zimbraCOSId: this.refs.zimbraCOSId.value,
zimbraAccountStatus: this.refs.zimbraAccountStatus.value
}; };
Client.createAccount( Client.createAccount(
this.refs.mail.value, email,
this.refs.mail.passwd, this.refs.passwd.value,
attrs, attrs,
(data) => { (data) => {
// reset form when all is ok // reset form when all is ok
document.getElementById('createAccount').reset(); document.getElementById('createAccount').reset();
this.setState( this.reset.toggleOptions();
{
error: `Su cuenta ${data.name} ha sido creada con èxito.`, MailboxStore.setMailbox(data);
GlobalActions.emitMessage({
message: 'Se ha creado su cuenta con éxito.',
typeError: messageType.SUCCESS typeError: messageType.SUCCESS
} });
);
}, },
(error) => { (error) => {
this.setState( GlobalActions.emitMessage({
{ message: error.message,
error: error.message, typeError: messageType.ERROR
typeError: messageType.WARNING });
}
);
} }
); );
return true;
}).catch((err) => { }).catch((err) => {
this.setState( GlobalActions.emitMessage({
message: err.message,
typeError: messageType.ERROR
});
err.node.focus();
});
}
handleRadioChanged(val) {
this.refs.zimbraCOSId.value = val;
}
getAllDomains() {
const promises = [];
const max = 200;
const doms = new Promise((resolve, reject) => {
Client.getAllDomains(
{ {
error: err.message, limit: max
typeError: err.typeError },
(data) => {
resolve(data);
},
(error) => {
reject(error);
} }
); );
});
err.node.focus(); const cos = new Promise((resolve, reject) => {
Client.getAllCos((success) => {
resolve(success);
}, (error) => {
reject(error);
});
}); });
promises.push(doms, cos);
Promise.all(promises).then((success) => {
const response = {};
success.map((pos) => {
if (Array.isArray(pos)) {
const arrPlans = Utils.getEnabledPlansByCos(pos);
response.plans = arrPlans;
} else {
response.domains = pos;
} }
return true;
});
componentDidMount() { this.setState(response);
/*$('#selectDomains').select2({
placeholder: 'Por favor, introduzca 3 caracteres.',
allowClear: true
});*/
$('#passwdMeter').pwstrength(); GlobalActions.emitEndLoading();
Utils.toggleStatusButtons('.action-save', false);
}, (error) => {
GlobalActions.emitMessage({
error: error.message,
typeError: error.type
});
GlobalActions.emitEndLoading();
Utils.toggleStatusButtons('.action-save', false);
});
}
componentDidMount() {
EventStore.addMessageListener(this.showMessage);
Utils.toggleStatusButtons('.action-save', true);
$('#sidebar-mailboxes').addClass('active'); $('#sidebar-mailboxes').addClass('active');
this.getAllDomains();
GlobalActions.emitEndLoading(); GlobalActions.emitEndLoading();
} }
componentWillUnmount() { componentWillUnmount() {
EventStore.removeMessageListener(this.showMessage);
$('#sidebar-mailboxes').removeClass('active'); $('#sidebar-mailboxes').removeClass('active');
} }
controllerDataList(controller) {
this.reset = controller;
}
render() { render() {
let message; let message;
let domains = [];
let form = null;
let checkboxes = [];
if (this.state.error) { if (this.state.error) {
message = ( message = (
<MessageBar <MessageBar
...@@ -94,7 +193,40 @@ export default class CreateMailBox extends React.Component { ...@@ -94,7 +193,40 @@ export default class CreateMailBox extends React.Component {
); );
} }
let form = ( if (this.state.domains) {
const object = this.state.domains.domain;
const plans = this.state.plans;
let limit = object.length;
for (; limit-- > 0;) {
domains.push(object[limit].name);
}
for (let plan in plans) {
if (plans.hasOwnProperty(plan)) {
const item = (
<label
className='radio radio-info radio-inline pretty-input'
key={plan}
>
<div className='pretty-radio'>
<input
type='radio'
className='pretty'
name='mailbox'
onChange={() => {
this.handleRadioChanged(plans[plan]);
}}
/>
<span></span>
</div>
{Utils.titleCase(plan)}
</label>
);
checkboxes.push(item);
}
}
form = (
<form <form
className='simple_form form-horizontal mailbox-form' className='simple_form form-horizontal mailbox-form'
onSubmit={(e) => { onSubmit={(e) => {
...@@ -110,23 +242,24 @@ export default class CreateMailBox extends React.Component { ...@@ -110,23 +242,24 @@ export default class CreateMailBox extends React.Component {
<div className='col-sm-8'> <div className='col-sm-8'>
<div className='row'> <div className='row'>
<div className='col-xs-6'> <div className='col-xs-12'>
<div className='input-group'>
<input <input
type='text' type='text'
className='form-control' className='form-control'
ref='mail' ref='mail'
data-required='true' data-required='true'
data-message='El nombre de la casilla es requerida, verifique por favor.'
placeholder='Mail'
/> />
</div>
<div className='col-xs-6'>
<div className='input-group'>
<span className='input-group-addon'>{'@'}</span> <span className='input-group-addon'>{'@'}</span>
<select <DataList
list='domain'
options={domains}
className='form-control' className='form-control'
id='selectDomains' placeholder='Dominio'
ref='domain' getController={this.controllerDataList}
> />
</select>
</div> </div>
</div> </div>
</div> </div>
...@@ -176,21 +309,19 @@ export default class CreateMailBox extends React.Component { ...@@ -176,21 +309,19 @@ export default class CreateMailBox extends React.Component {
</div> </div>
<div className='form-group string'> <div className='form-group string'>
<label className='string required col-sm-3 control-label'> <label className='string col-sm-3 control-label'>
{'Administrador delegado'} {'Status'}
</label> </label>
<div className='col-sm-8'> <div className='col-sm-8'>
<label className='radio-inline pretty-input'> <select
<div className='pretty-checkbox'> className='form-control'
<input ref='zimbraAccountStatus'
type='checkbox' >
className='pretty' <option value='active'>Activa</option>
ref='zimbraIsDelegatedAdminAccount' <option value='closed'>Cerrada</option>
/> <option value='locked'>Bloqueada</option>
<span></span> </select>
</div>
</label>
</div> </div>
</div> </div>
...@@ -201,44 +332,15 @@ export default class CreateMailBox extends React.Component { ...@@ -201,44 +332,15 @@ export default class CreateMailBox extends React.Component {
</label> </label>
<div className='col-sm-8'> <div className='col-sm-8'>
<label className='radio radio-info radio-inline pretty-input'>
<div className='pretty-radio'>
<input
type='radio'
className='pretty'
name='mailbox'
ref='mailbox_basic'
/>
<span></span>
</div>
{'Básica'}
</label>
<label className='radio radio-info radio-inline pretty-input'> {checkboxes}
<div className='pretty-radio'>
<input
type='radio'
className='pretty'
name='mailbox'
ref='mailbox_professional'
/>
<span></span>
</div>
{'Profesional'}
</label>
<label className='radio radio-info radio-inline pretty-input'>
<div className='pretty-radio'>
<input <input
type='radio' type='hidden'
className='pretty' ref='zimbraCOSId'
name='mailbox' data-required='true'
ref='mailbox_premium' data-message='El plan de su casilla es requerido, por favor verificar.'
/> />
<span></span>
</div>
{'Premium'}
</label>
</div> </div>
</div> </div>
...@@ -253,6 +355,7 @@ export default class CreateMailBox extends React.Component { ...@@ -253,6 +355,7 @@ export default class CreateMailBox extends React.Component {
type='password' type='password'
className='form-control' className='form-control'
data-required='true' data-required='true'
data-message='La contraseña de su casilla es requerida, verifique por favor.'
ref='passwd' ref='passwd'
id='passwdMeter' id='passwdMeter'
/> />
...@@ -265,7 +368,7 @@ export default class CreateMailBox extends React.Component { ...@@ -265,7 +368,7 @@ export default class CreateMailBox extends React.Component {
type='submit' type='submit'
name='commit' name='commit'
value='Guardar' value='Guardar'
className='btn btn-primary' className='btn btn-primary action-save'
/> />
<Button <Button
btnAttrs={ btnAttrs={
...@@ -283,6 +386,7 @@ export default class CreateMailBox extends React.Component { ...@@ -283,6 +386,7 @@ export default class CreateMailBox extends React.Component {
</div> </div>
</form> </form>
); );
}
const actions = [ const actions = [
{ {
...@@ -298,8 +402,8 @@ export default class CreateMailBox extends React.Component { ...@@ -298,8 +402,8 @@ export default class CreateMailBox extends React.Component {
return ( return (
<div> <div>
{message}
<div className='content animate-panel'> <div className='content animate-panel'>
{message}
<div className='row'> <div className='row'>
<div className='col-md-12 central-content'> <div className='col-md-12 central-content'>
<Panel <Panel
......
...@@ -6,10 +6,15 @@ import MessageBar from '../message_bar.jsx'; ...@@ -6,10 +6,15 @@ import MessageBar from '../message_bar.jsx';
import Panel from '../panel.jsx'; import Panel from '../panel.jsx';
import ConfirmDeleteModal from './confirm_delete_modal.jsx'; import ConfirmDeleteModal from './confirm_delete_modal.jsx';
import ToggleModalButton from '../toggle_modal_button.jsx'; import ToggleModalButton from '../toggle_modal_button.jsx';
import DataList from 'react-datalist';
import UserStore from '../../stores/user_store.jsx';
import Promise from 'bluebird';
import MailboxStore from '../../stores/mailbox_store.jsx';
import * as Client from '../../utils/client.jsx'; import * as Client from '../../utils/client.jsx';
import * as GlobalActions from '../../action_creators/global_actions.jsx'; import * as GlobalActions from '../../action_creators/global_actions.jsx';
import * as Utils from '../../utils/utils.jsx'; import * as Utils from '../../utils/utils.jsx';
import EventStore from '../../stores/event_store.jsx';
import Constants from '../../utils/constants.jsx'; import Constants from '../../utils/constants.jsx';
...@@ -23,12 +28,20 @@ export default class EditMailBox extends React.Component { ...@@ -23,12 +28,20 @@ export default class EditMailBox extends React.Component {
this.handleRadioChanged = this.handleRadioChanged.bind(this); this.handleRadioChanged = this.handleRadioChanged.bind(this);
this.getMailbox = this.getMailbox.bind(this); this.getMailbox = this.getMailbox.bind(this);
this.fillForm = this.fillForm.bind(this); this.fillForm = this.fillForm.bind(this);
this.showMessage = this.showMessage.bind(this);
this.state = {}; this.state = {};
} }
showMessage(attrs) {
this.setState({
error: attrs.message,
typeError: attrs.typeError
});
}
handleRadioChanged(val) { handleRadioChanged(val) {
this.refs.plan.value = val; this.refs.zimbraCOSId.value = val;
} }
handleEdit(e) { handleEdit(e) {
...@@ -36,41 +49,83 @@ export default class EditMailBox extends React.Component { ...@@ -36,41 +49,83 @@ export default class EditMailBox extends React.Component {
Utils.toggleStatusButtons('.action-button', true); Utils.toggleStatusButtons('.action-button', true);
Utils.validateInputRequired(this.refs).then(() => { Utils.validateInputRequired(this.refs).then(() => {
let attrs = { const domain = document.querySelector('input[list=\'domain\']');
if (domain.value === '') {
GlobalActions.emitMessage({
message: 'El dominio es requerido, verifique por favor.',
typeError: messageType.ERROR
});
domain.focus();
return false;
}
const email = this.refs.mail.value + '@' + domain.value;
// fill new attrs
const attrs = {
givenName: this.refs.givenName.value, givenName: this.refs.givenName.value,
sn: this.refs.sn.value sn: this.refs.sn.value,
description: this.refs.description.value,
zimbraCOSId: this.refs.zimbraCOSId.value,
zimbraAccountStatus: this.refs.zimbraAccountStatus.value
}; };
GlobalActions.emitStartLoading();
return new Promise((resolve, reject) => {
Client.modifyAccount( Client.modifyAccount(
this.state.data.id, this.props.params.id,
attrs, attrs,
(data) => { (account) => {
Utils.toggleStatusButtons('.action-button', false); return resolve(account);
this.setState(
{
error: `Su cuenta ${data.name} ha sido modificada con èxito.`,
typeError: messageType.SUCCESS,
data: data
}
);
}, },
(error) => { (error) => {
this.setState( return reject(error);
{
error: error.message,
typeError: messageType.WARNING
} }
); );
Utils.toggleStatusButtons('.action-button', false); }).then((account) => {
MailboxStore.changeAccount(account);
account.rename(email, (error, success) => {
if (error) {
this.setState({
data: account
});
return GlobalActions.emitMessage({
error: error.message,
typeError: messageType.ERROR
});
} }
);
const newAccount = MailboxStore.changeAccount(success);
this.setState({
data: newAccount
});
return GlobalActions.emitMessage({
message: `Su cuenta ${account.name} ha sido modificada con èxito.`,
typeError: messageType.SUCCESS
});
});
}).catch((error) => {
GlobalActions.emitMessage({
message: error.message,
typeError: messageType.ERROR
});
}).finally(() => {
GlobalActions.emitEndLoading();
Utils.toggleStatusButtons('.action-button', false);
});
}).catch((err) => { }).catch((err) => {
this.setState( GlobalActions.emitMessage({
{ message: err.message,
error: err.message, typeError: messageType.ERROR
typeError: err.typeError });
}
);
err.node.focus(); err.node.focus();
Utils.toggleStatusButtons('.action-button', false); Utils.toggleStatusButtons('.action-button', false);
...@@ -78,43 +133,151 @@ export default class EditMailBox extends React.Component { ...@@ -78,43 +133,151 @@ export default class EditMailBox extends React.Component {
} }
getMailbox(id) { getMailbox(id) {
Client.getAccount( const promises = [];
id, let data = null;
(data) => { const max = 200;
Utils.toggleStatusButtons('.action-save', true);
if (MailboxStore.hasMailboxes()) {
data = MailboxStore.getMailboxById(id);
const domains = new Promise((resolve, reject) => {
Client.getAllDomains(
{
limit: max
},
(dataDomains) => {
return resolve(dataDomains);
},
(error) => {
return reject(error);
}
);
});
const cos = new Promise((resolve, reject) => {
Client.getAllCos((success) => {
resolve(success);
}, (error) => {
reject(error);
});
});
promises.push(domains, cos);
Promise.all(promises).then((result) => {
this.setState({ this.setState({
data data,
domains: result.shift().domain,
cos: Utils.getEnabledPlansByCos(result.shift())
}); });
Utils.toggleStatusButtons('.action-save', false);
}).catch((error) => {
GlobalActions.emitMessage({
error: error.message,
typeError: error.type
});
}).finally(() => {
GlobalActions.emitEndLoading(); GlobalActions.emitEndLoading();
});
} else {
const mailbox = new Promise((resolve, reject) => {
Client.getAccount(
id,
(resultMailbox) => {
return resolve(resultMailbox);
}, },
(error) => { (error) => {
return reject(error);
}
);
});
const doms = new Promise((resolve, reject) => {
Client.getAllDomains(
{
limit: max
},
(domain) => {
return resolve(domain);
},
(error) => {
return reject(error);
}
);
});
const cos = new Promise((resolve, reject) => {
Client.getAllCos((success) => {
resolve(success);
}, (error) => {
reject(error);
});
});
promises.push(mailbox, doms, cos);
Promise.all(promises).then((result) => {
this.setState({ this.setState({
error: error.message data: result.shift(),
domains: result.shift().domain,
cos: Utils.getEnabledPlansByCos(result.shift())
}); });
Utils.toggleStatusButtons('.action-save', false);
}).catch((error) => {
GlobalActions.emitMessage({
error: error.message,
typeError: error.type
});
}).finally(() => {
GlobalActions.emitEndLoading(); GlobalActions.emitEndLoading();
});
} }
);
} }
componentDidMount() { componentDidMount() {
/*Client.renameAccount('nuevomodificado@zboxapp.dev', (exito) => {
console.log('exito', exito);
}, (fallo) => {
console.log('fallo', fallo);
});*/
$('#sidebar-mailboxes').addClass('active'); $('#sidebar-mailboxes').addClass('active');
GlobalActions.emitEndLoading(); EventStore.addMessageListener(this.showMessage);
this.getMailbox(this.props.params.id); this.getMailbox(this.props.params.id);
} }
componentWillUnmount() { componentWillUnmount() {
EventStore.removeMessageListener(this.showMessage);
$('#sidebar-mailboxes').removeClass('active'); $('#sidebar-mailboxes').removeClass('active');
} }
fillForm() { fillForm(data) {
let attrs = this.state.data.attrs; const attrs = data.attrs;
this.refs.mail.value = this.state.data.name; this.refs.mail.value = data.name.split('@').shift();
this.refs.givenName.value = attrs.givenName || ''; this.refs.givenName.value = attrs.givenName || '';
this.refs.sn.value = attrs.sn; this.refs.sn.value = attrs.sn;
this.refs.description.value = attrs.description || ''; this.refs.description.value = attrs.description || '';
this.refs.zimbraCOSId.value = attrs.zimbraCOSId || '';
this.refs.zimbraAccountStatus.value = attrs.zimbraAccountStatus;
} }
render() { render() {
let message; let message;
let data;
let actions;
let form;
const domains = [];
let buttonDelete = null;
let currentDomain = '';
const cosElements = [];
let datalist = (
<input
type='text'
className='form-control'
placeholder='Dominio'
/>
);
if (this.state.error) { if (this.state.error) {
message = ( message = (
<MessageBar <MessageBar
...@@ -125,13 +288,78 @@ export default class EditMailBox extends React.Component { ...@@ -125,13 +288,78 @@ export default class EditMailBox extends React.Component {
); );
} }
let data;
let actions;
let form;
if (this.state.data) { if (this.state.data) {
data = this.state.data; data = this.state.data;
this.fillForm(); const doms = this.state.domains;
const cos = this.state.cos;
currentDomain = data.name.split('@').pop();
buttonDelete = (
<ToggleModalButton
role='button'
className='btn btn-xs btn-danger action-button'
dialogType={ConfirmDeleteModal}
dialogProps={{data}}
key='delete-mailbox'
>
{'Eliminar'}
</ToggleModalButton>
);
const length = doms.length;
for (let i = 0; i < length; i++) {
domains.push(doms[i].name);
}
for (let cosName in cos) {
if (cos.hasOwnProperty(cosName)) {
let isChecked = false;
const id = data.attrs.zimbraCOSId;
if (id) {
if (cos[cosName] === id) {
isChecked = 'checked';
}
}
const checkbox = (
<label
key={cos[cosName]}
className='radio radio-info radio-inline pretty-input'
>
<div className='pretty-radio'>
<input
type='radio'
className='pretty'
name='mailbox'
defaultChecked={isChecked}
onChange={() => {
this.handleRadioChanged(cos[cosName]);
}}
/>
<span></span>
</div>
{cosName}
</label>
);
cosElements.push(checkbox);
}
}
if (UserStore.getCurrentUser().name === data.name) {
buttonDelete = null;
}
this.fillForm(data);
datalist = (
<DataList
list='domain'
options={domains}
className='form-control'
placeholder='Dominio'
initialFilter={currentDomain}
/>
);
} }
form = ( form = (
...@@ -150,24 +378,17 @@ export default class EditMailBox extends React.Component { ...@@ -150,24 +378,17 @@ export default class EditMailBox extends React.Component {
<div className='col-sm-8'> <div className='col-sm-8'>
<div className='row'> <div className='row'>
<div className='col-xs-6'> <div className='col-xs-12'>
<div className='input-group'>
<input <input
type='text' type='text'
className='form-control' className='form-control'
ref='mail' ref='mail'
data-required='true' data-required='true'
data-message='El campo direccion es requerido, verifique por favor.' placeholder='Mail'
/> />
</div>
<div className='col-xs-6'>
<div className='input-group'>
<span className='input-group-addon'>{'@'}</span> <span className='input-group-addon'>{'@'}</span>
<select {datalist}
className='form-control'
id='selectDomains'
ref='domain'
>
</select>
</div> </div>
</div> </div>
</div> </div>
...@@ -217,60 +438,34 @@ export default class EditMailBox extends React.Component { ...@@ -217,60 +438,34 @@ export default class EditMailBox extends React.Component {
</div> </div>
<div className='form-group string'> <div className='form-group string'>
<label className='string required col-sm-3 control-label'> <label className='string col-sm-3 control-label'>
<abbr title='Requerido'>{'*'}</abbr> {'Status'}
{'Tipo de casilla'}
</label> </label>
<div className='col-sm-8'> <div className='col-sm-8'>
<label className='radio radio-info radio-inline pretty-input'> <select
<div className='pretty-radio'> className='form-control'
<input ref='zimbraAccountStatus'
type='radio' >
className='pretty' <option value='active'>Activa</option>
name='mailbox' <option value='closed'>Cerrada</option>
onChange={() => { <option value='locked'>Bloqueada</option>
this.handleRadioChanged('basica'); </select>
}}
/>
<span></span>
</div> </div>
{'Básica'}
</label>
<label className='radio radio-info radio-inline pretty-input'>
<div className='pretty-radio'>
<input
className='pretty'
name='mailbox'
type='radio'
onChange={() => {
this.handleRadioChanged('profesional');
}}
/>
<span></span>
</div> </div>
{'Profesional'}
</label>
<label className='radio radio-info radio-inline pretty-input'> <div className='form-group string'>
<div className='pretty-radio'> <label className='string required col-sm-3 control-label'>
<input <abbr title='Requerido'>{'*'}</abbr>
type='radio' {'Tipo de casilla'}
className='pretty'
name='mailbox'
onChange={() => {
this.handleRadioChanged('premium');
}}
/>
<span></span>
</div>
{'Premium'}
</label> </label>
<div className='col-sm-8'>
{cosElements}
<input <input
type='hidden' type='hidden'
ref='plan' ref='zimbraCOSId'
data-required='true' data-required='true'
data-message='El plan de su cuenta es requerido, por favor verificar.' data-message='El plan de su cuenta es requerido, por favor verificar.'
/> />
...@@ -314,24 +509,14 @@ export default class EditMailBox extends React.Component { ...@@ -314,24 +509,14 @@ export default class EditMailBox extends React.Component {
} }
}, },
{ {
setComponent: ( setComponent: buttonDelete
<ToggleModalButton
role='button'
className='btn btn-xs btn-danger action-button'
dialogType={ConfirmDeleteModal}
dialogProps={{data}}
key='delete-mailbox'
>
{'Eliminar'}
</ToggleModalButton>
)
} }
]; ];
return ( return (
<div> <div>
{message}
<div className='content animate-panel'> <div className='content animate-panel'>
{message}
<div className='row'> <div className='row'>
<div className='col-md-12 central-content'> <div className='col-md-12 central-content'>
<Panel <Panel
......
import React from 'react';
import Datalist from 'react-datalist';
import Button from '../button.jsx';
import * as Utils from '../../utils/utils.jsx';
import * as GlobalActions from '../../action_creators/global_actions.jsx';
import Constants from '../../utils/constants.jsx';
const typeErrors = Constants.MessageType;
export default class FormAliasMailbox extends React.Component {
constructor(props) {
super(props);
this.handleDeleteAlias = this.handleDeleteAlias.bind(this);
this.sortAlias = this.sortAlias.bind(this);
this.addAlias = this.addAlias.bind(this);
this.toggleClass = 'glyphicon-sort-by-attributes';
this.asc = true;
this.state = {
alias: this.getAlias()
};
}
addAlias(e) {
e.preventDefault();
const refs = this.refs;
const newAlias = refs.alias.value + '@' + refs.domain.value;
Utils.validateInputRequired(refs).then(() => {
this.props.data.addAccountAlias(newAlias, () => {
GlobalActions.emitMessage({
message: 'Se ha agregado su nuevo Alias con éxito.',
type: typeErrors.SUCCESS
});
let alias = this.state.alias;
alias.push(newAlias);
this.setState({
alias: alias
});
}, (err) => {
GlobalActions.emitMessage({
message: err.error,
type: typeErrors.ERROR
});
});
}, (error) => {
GlobalActions.emitMessage({
message: error.message,
type: typeErrors.ERROR
});
error.node.focus();
});
}
sortAlias() {
let sort;
if (this.asc) {
sort = this.state.alias;
sort.sort().reverse();
this.setState({
alias: sort
});
this.asc = false;
this.toggleClass = 'glyphicon-sort-by-attributes';
} else {
sort = this.state.alias;
sort.sort();
this.setState({
alias: sort
});
this.asc = true;
this.toggleClass = 'glyphicon-sort-by-attributes-alt';
}
}
handleDeleteAlias(e, alias, index) {
e.preventDefault();
this.props.data.removeAccountAlias(alias, () => {
GlobalActions.emitMessage({
message: 'Se ha eliminado el alias éxitosamente.',
type: typeErrors.SUCCESS
});
const newAlias = Utils.removeIndexFromArray(this.state.alias, index);
this.setState({
alias: newAlias
});
}, (err) => {
GlobalActions.emitMessage({
message: err.error,
type: typeErrors.ERROR
});
});
}
getAlias() {
const data = this.props.data;
if (data.attrs.hasOwnProperty('zimbraMailAlias')) {
if (typeof data.attrs.zimbraMailAlias === 'string') {
return new Array(data.attrs.zimbraMailAlias);
}
return data.attrs.zimbraMailAlias.sort();
}
return [];
}
componentDidMount() {
let refs = this.refs;
refs.domain = refs.domain.refs.theInput;
refs.domain.setAttribute('data-required', 'true');
refs.domain.setAttribute('data-message', 'El dominio es necesario para crear el alias, verifiquelo por favor.');
}
render() {
let tbody;
let results;
// this bellow is just for testing porpuse
let options = ['apple', 'orange', 'pear', 'pineapple', 'melon'];
if (this.state.alias) {
tbody = this.state.alias.map((alias, i) => {
return (
<tr
key={`alias-${alias}-${i}`}
>
<td>
<span>{alias}</span>
<Button
btnAttrs={{
className: 'pull-right',
title: `Borrar el siguiente Alias : ${alias}`,
onClick: (e) => {
this.handleDeleteAlias(e, alias, i);
}
}}
>
<i className='fa fa-minus-circle text-danger'></i>
</Button>
</td>
</tr>
);
});
}
results = (
<table className='table table-striped table-bordered table-hover dataTable no-footer'>
<thead>
<tr>
<th>
{'Nombre'}
<span className='pull-right'>
<i
className={`glyphicon ${this.toggleClass} pull-right pointer`}
onClick={() => {
this.sortAlias();
}}
>
</i>
</span>
</th>
</tr>
</thead>
<tbody>
{tbody}
</tbody>
</table>
);
return (
<div className='row'>
<div className='col-xs-6'>
<div className='row'>
<form className='form-inline'>
<div className='col-xs-4'>
<div className='form-group'>
<label>
{'Mostrar'}
<select
ref='shown'
className='form-control input-sm'
>
<option value='10'>10</option>
<option value='25'>25</option>
<option value='50'>50</option>
<option value='100'>100</option>
</select>
</label>
</div>
</div>
<div className='col-xs-8 text-right'>
<label>
{'Buscar'}
<input
type='search'
className='form-control input-sm'
ref='search'
/>
</label>
</div>
</form>
</div>
<div className='row'>
<div className='col-xs-12'>
{results}
</div>
</div>
<div className='row'>
<div className='col-xs-6'>
<div className='dataTables_info'>
1 al 2 de 2 resultados
</div>
</div>
<div className='col-xs-6 text-right'>
<div className='btn-group'>
<Button
btnAttrs={
{
className: 'btn btn-default'
}
}
>
{'Anterior'}
</Button>
<Button
btnAttrs={
{
className: 'btn btn-default'
}
}
>
{'Siguiente'}
</Button>
</div>
</div>
</div>
</div>
<div className='col-xs-6'>
<div className='input-group'>
<input
type='text'
ref='alias'
className='form-control'
placeholder='Alias'
data-required='true'
data-message='El alias es requerido, compruebelo por favor'
/>
<span className='input-group-addon'>
@
</span>
<Datalist
list='domains'
options={options}
className='form-control'
id='domain'
ref='domain'
placeholder='Dominio'
/>
<span className='input-group-btn'>
<Button
btnAttrs={
{
className: 'btn btn-default',
onClick: (e) => {
this.addAlias(e);
}
}
}
>
Agregar alias
</Button>
</span>
</div>
</div>
</div>
);
}
}
FormAliasMailbox.propTypes = {
data: React.PropTypes.object
};
...@@ -30,12 +30,12 @@ export default class FormVacacionesMailbox extends React.Component { ...@@ -30,12 +30,12 @@ export default class FormVacacionesMailbox extends React.Component {
Client.modifyAccount(data.id, attrs, () => { Client.modifyAccount(data.id, attrs, () => {
GlobalActions.emitMessage({ GlobalActions.emitMessage({
message: 'Se ha modificado con éxito', error: 'Se ha modificado su respuesta de vacaciones con éxito.',
type: messageType.SUCCESS type: messageType.SUCCESS
}); });
}, (error) => { }, (error) => {
GlobalActions.emitMessage({ GlobalActions.emitMessage({
message: error.message, error: error.message,
type: messageType.ERROR type: messageType.ERROR
}); });
}); });
......
import React from 'react'; import React from 'react';
import Button from '../button.jsx'; import Button from '../button.jsx';
import StatusLabel from '../status_label.jsx';
import * as Client from '../../utils/client.jsx'; import * as Client from '../../utils/client.jsx';
import * as Utils from '../../utils/utils.jsx'; import * as Utils from '../../utils/utils.jsx';
import * as GlobalActions from '../../action_creators/global_actions.jsx';
import ZimbraStore from '../../stores/zimbra_store.jsx';
export default class BlockGeneralInfoMailbox extends React.Component { export default class BlockGeneralInfoMailbox extends React.Component {
constructor(props) { constructor(props) {
...@@ -16,24 +19,22 @@ export default class BlockGeneralInfoMailbox extends React.Component { ...@@ -16,24 +19,22 @@ export default class BlockGeneralInfoMailbox extends React.Component {
this.state = {}; this.state = {};
} }
componentWillMount() {
this.domain = this.props.data.name.split('@');
this.domain = this.domain[this.domain.length - 1];
}
componentDidMount() { componentDidMount() {
this.getDomain(); this.getDomain();
} }
getDomain() { getDomain() {
Client.getDomain(this.domain, (data) => { const domain = Utils.getDomainFromString(this.data.name);
Client.getDomain(domain, (data) => {
this.setState({ this.setState({
hasDomain: true, hasDomain: true,
domainData: data domainData: data
}); });
}, (error) => { }, (error) => {
this.setState({ GlobalActions.emitMessage({
error: error.message error: error.message,
typeError: error.type
}); });
}); });
} }
...@@ -44,25 +45,64 @@ export default class BlockGeneralInfoMailbox extends React.Component { ...@@ -44,25 +45,64 @@ export default class BlockGeneralInfoMailbox extends React.Component {
render() { render() {
let blockInfo = null; let blockInfo = null;
let statusCos = null;
const cosID = Utils.getEnabledPlansObjectByCos(ZimbraStore.getAllCos(), this.props.data.attrs.zimbraCOSId);
let cosName = null;
switch (cosID.name) {
case 'premium':
cosName = Utils.titleCase(cosID.name);
statusCos = 'label btn-primary2 btn-xs';
break;
case 'professional':
cosName = Utils.titleCase(cosID.name);
statusCos = 'label btn-primary btn-xs';
break;
case 'basic':
cosName = Utils.titleCase(cosID.name);
statusCos = 'label btn-success btn-xs';
break;
default:
cosName = 'Sin Plan';
statusCos = 'label noplan btn-xs';
break;
}
if (this.state.hasDomain) { if (this.state.hasDomain) {
const data = this.props.data;
const attrs = this.props.data.attrs;
const owner = (!attrs.givenName || !attrs.sn) ? null : attrs.givenName + ' ' + attrs.sn;
const mail = data.name;
//properties
const description = attrs.description;
const mailhost = attrs.zimbraMailHost;
const archive = attrs.zimbraArchiveAccount;
blockInfo = ( blockInfo = (
<article> <article className='account-info'>
<div> <div>
<h4> <h4>
<span className='mailbox-name text-success'>{this.data.name}</span> <span className='mailbox-name text-success'>{mail}</span>
</h4> </h4>
{owner && (
<h5>
{owner}
</h5>
)}
</div> </div>
{description && (
<div> <div>
<p> <p>
{this.data.attrs.description} {description}
</p> </p>
</div> </div>
)}
<div> <div>
<p> <p>
<strong>{'Dominio'}: </strong> <strong>{'Dominio: '}</strong>
<Button <Button
btnAttrs={{ btnAttrs={{
onClick: (e) => { onClick: (e) => {
...@@ -70,10 +110,36 @@ export default class BlockGeneralInfoMailbox extends React.Component { ...@@ -70,10 +110,36 @@ export default class BlockGeneralInfoMailbox extends React.Component {
} }
}} }}
> >
{this.domain} {this.state.domainData.name}
</Button> </Button>
</p> </p>
</div> </div>
{archive && (
<div>
<p>
<strong>{'Archive: '}</strong>
{archive}
</p>
</div>
)}
{mailhost && (
<div>
<p>
<strong>{'Mail Host'}: </strong>
{mailhost}
</p>
</div>
)}
<div>
<p>
<StatusLabel classes={statusCos}>
{cosName}
</StatusLabel>
</p>
</div>
</article> </article>
); );
} }
......
...@@ -3,15 +3,17 @@ ...@@ -3,15 +3,17 @@
import $ from 'jquery'; import $ from 'jquery';
import React from 'react'; import React from 'react';
import {browserHistory} from 'react-router'; import Promise from 'bluebird';
import EventStore from '../../stores/event_store.jsx';
import Button from '../button.jsx';
import MessageBar from '../message_bar.jsx';
import PageInfo from '../page_info.jsx'; import PageInfo from '../page_info.jsx';
import Panel from '../panel.jsx'; import Panel from '../panel.jsx';
import PanelTab from '../panel_tab.jsx'; import PanelTab from '../panel_tab.jsx';
import Pagination from '../pagination.jsx'; import Pagination from '../pagination.jsx';
import MailboxStore from '../../stores/mailbox_store.jsx';
import Button from '../button.jsx';
import statusLabel from '../status_label.jsx'; import statusLabel from '../status_label.jsx';
import MessageBar from '../message_bar.jsx';
import * as Client from '../../utils/client.jsx'; import * as Client from '../../utils/client.jsx';
import * as GlobalActions from '../../action_creators/global_actions.jsx'; import * as GlobalActions from '../../action_creators/global_actions.jsx';
...@@ -27,14 +29,7 @@ export default class Mailboxes extends React.Component { ...@@ -27,14 +29,7 @@ export default class Mailboxes extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.handleEdit = this.handleEdit.bind(this); this.showMessage = this.showMessage.bind(this);
this.getMailboxes = this.getMailboxes.bind(this);
this.handleAddMailbox = this.handleAddMailbox.bind(this);
this.handleExportAsCSV = this.handleExportAsCSV.bind(this);
this.handleTabChanged = this.handleTabChanged.bind(this);
this.handleWatchInfo = this.handleWatchInfo.bind(this);
this.domainInfo = this.domainInfo.bind(this);
const page = parseInt(this.props.location.query.page, 10) || 1; const page = parseInt(this.props.location.query.page, 10) || 1;
this.state = { this.state = {
...@@ -43,6 +38,47 @@ export default class Mailboxes extends React.Component { ...@@ -43,6 +38,47 @@ export default class Mailboxes extends React.Component {
}; };
} }
showMessage(attrs) {
this.setState({
error: attrs.error,
type: attrs.typeError
});
}
handleExportAsCSV(e) {
e.preventDefault();
const accounts = MailboxStore.getMailboxes();
if (accounts && accounts.account && accounts.account.length > 0) {
return Utils.exportAsCSV(accounts.account, 'all_accounts', true);
}
return false;
}
componentWillReceiveProps(newProps) {
const condition = this.props.location.query.page !== newProps.location.query.page;
if (condition) {
const page = parseInt(newProps.location.query.page, 10) || 1;
GlobalActions.emitStartLoading();
this.state = {
page,
offset: ((page - 1) * QueryOptions.DEFAULT_LIMIT)
};
this.getAllMailboxes();
} else {
GlobalActions.emitStartLoading();
let domainId;
if (newProps.params.domain_id !== this.props.params.domain_id) {
domainId = newProps.params.domain_id;
}
this.getAllMailboxes(domainId);
}
}
domainInfo(domainId) { domainInfo(domainId) {
return new Promise( return new Promise(
(resolve, reject) => { (resolve, reject) => {
...@@ -65,131 +101,82 @@ export default class Mailboxes extends React.Component { ...@@ -65,131 +101,82 @@ export default class Mailboxes extends React.Component {
); );
} }
handleWatchInfo(e, path, location) { getAccounts(domainName) {
Utils.handleLink(e, path, location); const attrs = {};
if (domainName) {
attrs.domain = domainName;
} }
getAccounts(domainName) { new Promise((resolve, reject) => {
Client.getAllAccounts( if (domainName) {
{ return Client.getAllAccounts(attrs, (success) => {
limit: QueryOptions.DEFAULT_LIMIT, return resolve(success);
offset: this.state.offset, }, (error) => {
domain: domainName return reject(error);
},
(data) => {
this.setState({
data
});
GlobalActions.emitEndLoading();
},
(error) => {
this.setState({
error: error.message
}); });
GlobalActions.emitEndLoading();
}
);
} }
getMailboxes() { if (MailboxStore.hasMailboxes()) {
const domainId = this.props.params.domain_id; resolve(MailboxStore.getMailboxes());
if (domainId) {
return this.domainInfo(domainId).then(
() => {
const domain = DomainStore.getCurrent();
this.getAccounts(domain.name);
}
);
} }
return this.getAccounts(); return Client.getAllAccounts(attrs, (success) => {
MailboxStore.setMailboxes(success);
return resolve(success);
}, (error) => {
return reject(error);
});
}).then((data) => {
if (data.account) {
const tables = this.buildTableFromData(data, ['Todas', 'Bloqueadas']);
if (tables.lockedAlert) {
GlobalActions.emitMessage({
error: tables.lockedAlert.message,
typeError: messageType.LOCKED
});
} }
handleAddMailbox(e, path) { return this.setState({
e.preventDefault(); data: tables
if ((this.props.location.basename + this.props.location.pathname) !== path) { });
browserHistory.push(path);
GlobalActions.emitStartLoading();
}
} }
handleExportAsCSV(e) { return this.setState({
e.preventDefault(); domainNotFound: domainName
});
}).catch(() => {
//console.log(error);
}).finally(() => {
GlobalActions.emitEndLoading();
});
} }
handleTabChanged(tab) { getAllMailboxes(domainId) {
browserHistory.push(this.props.location.pathname + '?tab=' + tab); if (domainId) {
return this.domainInfo(domainId).then(() => {
const domain = DomainStore.getCurrent();
this.getAccounts(domain.name);
});
} }
componentWillReceiveProps(newProps) { return this.getAccounts();
if (this.props.location.query.page !== newProps.location.query.page) {
const page = parseInt(newProps.location.query.page, 10) || 1;
GlobalActions.emitStartLoading();
this.state = {
page,
offset: ((page - 1) * QueryOptions.DEFAULT_LIMIT)
};
this.getMailboxes();
}
} }
componentDidMount() { componentDidMount() {
$('#sidebar-mailboxes').addClass('active'); $('#sidebar-mailboxes').addClass('active');
this.getMailboxes(); EventStore.addMessageListener(this.showMessage);
const domainId = this.props.params.domain_id;
this.getAllMailboxes(domainId);
} }
componentWillUnmount() { componentWillUnmount() {
EventStore.removeMessageListener(this.showMessage);
$('#sidebar-mailboxes').removeClass('active'); $('#sidebar-mailboxes').removeClass('active');
} }
handleEdit(e, path) { buildRow(row, classes, status) {
e.preventDefault(); const id = row.id;
if ((this.props.location.basename + this.props.location.pathname) !== path) {
GlobalActions.emitStartLoading();
browserHistory.push(path);
}
}
render() {
let message;
let panelTabs;
if (this.state.error) {
message = (
<MessageBar
message={this.state.error}
type={messageType.SUCCESS}
autoclose={true}
/>
);
}
let tableResults;
let total = 0;
const arrLocked = [];
if (this.state.data) {
const accounts = this.state.data.account || [];
total = accounts.length;
tableResults = accounts.map((mail) => {
let attrs = mail.attrs;
let statusClass = '';
let status = attrs.zimbraAccountStatus;
let id = mail.id;
switch (status) {
case 'locked':
statusClass = 'label label-warning';
status = 'Bloqueada';
arrLocked.push(mail);
break;
default:
statusClass = 'label label-success';
status = 'Activa';
break;
}
return ( return (
<tr <tr
key={id} key={id}
...@@ -197,25 +184,25 @@ export default class Mailboxes extends React.Component { ...@@ -197,25 +184,25 @@ export default class Mailboxes extends React.Component {
id={id} id={id}
> >
<td className={'mailbox-name'}> <td className={'mailbox-name'}>
<statusLabel className={statusClass}>{status}</statusLabel> <statusLabel className={classes}>{status}</statusLabel>
<Button <Button
btnAttrs={{ btnAttrs={
{
className: 'mailbox-link', className: 'mailbox-link',
onClick: (e) => { onClick: (e) => Utils.handleLink(e, 'mailboxes/' + id)
this.handleWatchInfo(e, `mailboxes/${mail.id}`, location); }
} }
}}
> >
{mail.name} {row.name}
</Button> </Button>
</td> </td>
<td className={'mailbox-displayname'}> <td className={'mailbox-displayname'}>
{mail.name} {row.name}
</td> </td>
<td className={'mailbox-cos-plan'}> <td className={'mailbox-cos-plan'}>
<statusLabel className={'label-plan label-unknown'}>unknown</statusLabel> <statusLabel className={'label-plan label-unknown'}>{'unknown'}</statusLabel>
</td> </td>
<td> <td>
...@@ -223,9 +210,7 @@ export default class Mailboxes extends React.Component { ...@@ -223,9 +210,7 @@ export default class Mailboxes extends React.Component {
btnAttrs={ btnAttrs={
{ {
className: 'btn btn-xs btn-default', className: 'btn btn-xs btn-default',
onClick: (e) => { onClick: (e) => Utils.handleLink(e, '/mailboxes/' + id + '/edit')
this.handleEdit(e, '/mailboxes/' + mail.id + '/edit');
}
} }
} }
> >
...@@ -234,11 +219,25 @@ export default class Mailboxes extends React.Component { ...@@ -234,11 +219,25 @@ export default class Mailboxes extends React.Component {
</td> </td>
</tr> </tr>
); );
}); }
makeTable(rows, page) {
const hasPage = page || false;
let pagination = null;
if (hasPage) {
pagination = (
<Pagination
key='panelPagination'
url='mailboxes'
currentPage={this.state.page}
totalPages={hasPage.total}
/>
);
}
const panelBody = ( return (
<div <div
key='mailboxes-body' key='mailbox'
id='index-mailboxes-table' id='index-mailboxes-table'
className='table-responsive' className='table-responsive'
> >
...@@ -257,51 +256,67 @@ export default class Mailboxes extends React.Component { ...@@ -257,51 +256,67 @@ export default class Mailboxes extends React.Component {
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{tableResults} {rows}
</tbody> </tbody>
</table> </table>
{pagination}
</div> </div>
); );
}
const todas = `Todas (${total})`; insertToPanel(table, id, btns) {
const archiving = 'Archiving'; const btn = btns || [];
const noPlan = `Sin Plan (${total})`;
const locked = `Bloqueada (${arrLocked.length})`;
const arrTabNames = [
todas,
archiving,
noPlan,
locked
];
let pagination; return (
if (this.state.offset > 0 || (this.state.data && this.state.data.more)) { <Panel
const totalPages = this.state.data ? Math.ceil(this.state.data.total / QueryOptions.DEFAULT_LIMIT) : 0; children={table}
const tab = this.props.location.query.tab || Utils.slug(todas); key={id}
pagination = ( btnsHeader={btn}
<Pagination
key='panelPagination'
url={`mailboxes?tab=${tab}`}
currentPage={this.state.page}
totalPages={totalPages}
/> />
); );
} }
buildTableFromData(data, arrayTabNames) {
if (data.account) {
const accounts = data.account;
const totalAccounts = data.total;
const limit = data.account.length;
let activeAccounts = [];
let lockedAccounts = [];
const tabs = {};
for (let i = 0; i < limit; i++) {
const account = accounts[i].attrs;
switch (account.zimbraAccountStatus) {
case 'active':
activeAccounts.push(this.buildRow(accounts[i], 'label label-success m-r', 'Activa'));
break;
case 'closed':
activeAccounts.push(this.buildRow(accounts[i], 'label label-default m-r', 'Cerrada'));
break;
case 'locked':
activeAccounts.push(this.buildRow(accounts[i], 'label label-warning m-r', 'Inactiva'));
break;
case 'lockedout':
lockedAccounts.push(this.buildRow(accounts[i], 'label label-locked m-r', 'Bloqueada'));
activeAccounts.push(this.buildRow(accounts[i], 'label label-locked m-r', 'Bloqueada'));
break;
}
}
const response = {};
const all = `${arrayTabNames.shift()} (${activeAccounts.length})`;
const locked = `${arrayTabNames.shift()} (${lockedAccounts.length})`;
// create structure html for all accountsç
const icon = ( const icon = (
<div> <div>
<i className='/fa fa-download'/> <i className='fa fa-download'/>
<span>{'Exportar'}</span> <span>{'Exportar'}</span>
</div> </div>
); );
const tab1 = ( const btn = [
<div>
<Panel
title=''
children={[panelBody, pagination]}
btnsHeader={[
{ {
props: { props: {
className: 'btn btn-default', className: 'btn btn-default',
...@@ -314,82 +329,101 @@ export default class Mailboxes extends React.Component { ...@@ -314,82 +329,101 @@ export default class Mailboxes extends React.Component {
{ {
props: { props: {
className: 'btn btn-success', className: 'btn btn-success',
onClick: (e) => { onClick: (e) => Utils.handleLink(e, '/mailboxes/new')
this.handleAddMailbox(e, '/mailboxes/new');
}
}, },
label: '+ Nueva Casilla' label: '+ Nueva Casilla'
} }
]} ];
/>
</div>
);
const tab2 = ( let activePagination = null;
<Panel const totalPage = Math.ceil(totalAccounts / QueryOptions.DEFAULT_LIMIT);
title='Casillas tab2' if (activeAccounts.length > QueryOptions.DEFAULT_LIMIT) {
children={[panelBody, pagination]} activeAccounts = activeAccounts.slice(this.state.offset, (this.state.page * QueryOptions.DEFAULT_LIMIT));
/> activePagination = {
); total: totalPage
};
}
const tab3 = ( let lockedPagination = null;
<Panel if (lockedAccounts.length > QueryOptions.DEFAULT_LIMIT) {
title='Casillas tb3' lockedAccounts = lockedAccounts.slice(this.state.offset, (this.state.page * QueryOptions.DEFAULT_LIMIT));
children={panelBody} lockedPagination = {
total: totalPage
};
}
const tableActive = this.makeTable(activeAccounts, activePagination);
const panelActive = this.insertToPanel(tableActive, 'panel-all', btn);
// create structure html for all locked accounts
const tableLocked = this.makeTable(lockedAccounts, lockedPagination);
const panelLocked = this.insertToPanel(tableLocked, 'panel-locked');
arrayTabNames.push(all, locked);
tabs[Utils.slug(all)] = panelActive;
tabs[Utils.slug(locked)] = panelLocked;
response.tabNames = arrayTabNames;
response.tabs = tabs;
if (lockedAccounts.length > 0) {
const isPlural = (lockedAccounts.length > 1) ? true : null;
response.lockedAlert = {
total: lockedAccounts.length,
message: (isPlural) ? `${lockedAccounts.length} casillas bloqueadas` : `${lockedAccounts.length} casilla bloqueada`
};
}
return response;
}
return false;
}
render() {
let message = null;
if (this.state.error) {
message = (
<MessageBar
message={this.state.error}
type={this.state.type}
autoclose={false}
/> />
); );
}
const tab4 = ( let content = (
<Panel <div className='text-center'>
title='Casillas tab4' <h4>
children={panelBody} No se han encontrado casillas para el dominio : {this.state.domainNotFound}
</h4>
</div>
);
const pagelInfo = (
<PageInfo
titlePage='Casillas'
descriptionPage='Usuarios de correo electrónico'
/> />
); );
const arrTabs = {}; if (this.state.data) {
arrTabs[Utils.slug(todas)] = tab1; const data = this.state.data;
arrTabs[Utils.slug(archiving)] = tab2;
arrTabs[Utils.slug(noPlan)] = tab3;
arrTabs[Utils.slug(locked)] = tab4;
panelTabs = ( content = (
<PanelTab <PanelTab
tabNames={arrTabNames} tabNames={data.tabNames}
tabs={arrTabs} tabs={data.tabs}
location={this.props.location} location={this.props.location}
onClick={this.handleTabChanged} onClick={this.handleTabChanged}
/> />
); );
} }
const content = panelTabs || '';
let title = 'Casillas';
const domain = DomainStore.getCurrent();
if (this.props.params.domain_id && domain) {
title = (
<div>
{'Casillas del dominio: '}
<a
href='#'
onClick={(e) => Utils.handleLink(e, `/domains/${domain.id}`)}
>
{`@${domain.name}`}
</a>
</div>
);
}
return ( return (
<div> <div>
<PageInfo {pagelInfo}
titlePage={title}
descriptionPage='Usuarios de correo electrónico'
/>
{message}
<div className='content animate-panel'> <div className='content animate-panel'>
{message}
<div className='row'> <div className='row'>
<div className='col-md-12 panel-with-tabs'> <div className='col-md-12 panel-with-tabs'>
{content} {content}
......
...@@ -12,14 +12,19 @@ import Panel from '../panel.jsx'; ...@@ -12,14 +12,19 @@ import Panel from '../panel.jsx';
import BlockGeneralInfoMailbox from './info_general_mailbox.jsx'; import BlockGeneralInfoMailbox from './info_general_mailbox.jsx';
import BlockStatsMailbox from './stats_mailbox.jsx'; import BlockStatsMailbox from './stats_mailbox.jsx';
import FormVacacionesMailbox from './form_resp_vacaciones_mailbox.jsx'; import FormVacacionesMailbox from './form_resp_vacaciones_mailbox.jsx';
import FormAliasMailbox from './form_alias_mailbox.jsx'; import FormAliasMailbox from './../panel_actions.jsx';
import ChangePasswordModal from './change_passwd_modal.jsx'; import ChangePasswordModal from './change_passwd_modal.jsx';
import ToggleModalButton from '../toggle_modal_button.jsx'; import ToggleModalButton from '../toggle_modal_button.jsx';
import MessageBar from '../message_bar.jsx'; import MessageBar from '../message_bar.jsx';
import Promise from 'bluebird';
import MailboxStore from '../../stores/mailbox_store.jsx';
import * as Client from '../../utils/client.jsx'; import * as Client from '../../utils/client.jsx';
import * as Utils from '../../utils/utils.jsx'; import * as Utils from '../../utils/utils.jsx';
import * as GlobalActions from '../../action_creators/global_actions.jsx'; import * as GlobalActions from '../../action_creators/global_actions.jsx';
import Constants from '../../utils/constants.jsx';
const MessageTypes = Constants.MessageType;
export default class MailboxDetails extends React.Component { export default class MailboxDetails extends React.Component {
constructor(props) { constructor(props) {
...@@ -28,6 +33,8 @@ export default class MailboxDetails extends React.Component { ...@@ -28,6 +33,8 @@ export default class MailboxDetails extends React.Component {
this.getMailbox = this.getMailbox.bind(this); this.getMailbox = this.getMailbox.bind(this);
this.handleEdit = this.handleEdit.bind(this); this.handleEdit = this.handleEdit.bind(this);
this.showMessage = this.showMessage.bind(this); this.showMessage = this.showMessage.bind(this);
this.onRemoveAlias = this.onRemoveAlias.bind(this);
this.onCancelAlias = this.onCancelAlias.bind(this);
this.state = {}; this.state = {};
} }
...@@ -36,40 +43,97 @@ export default class MailboxDetails extends React.Component { ...@@ -36,40 +43,97 @@ export default class MailboxDetails extends React.Component {
Utils.handleLink(e, path, location); Utils.handleLink(e, path, location);
} }
exportAsCSV(data) {
Utils.exportAsCSV(data, 'mailboxes_alias', true);
}
showMessage(attrs) { showMessage(attrs) {
this.setState({ this.setState({
error: attrs.message, error: attrs.error,
type: attrs.type.toLowerCase(), type: attrs.typeError
autocloseInSecs: 10
}); });
} }
getMailbox() { onRemoveAlias(alias) {
const id = this.props.params.id; MailboxStore.removeAlias(alias);
Utils.toggleStatusButtons('.action-info-btns', true);
const items = MailboxStore.getAlias();
Client.getAccount(id, (data) => {
this.setState({ this.setState({
data alias: items,
error: false
});
}
onCancelAlias(arrAlias) {
MailboxStore.refreshAlias(arrAlias);
const items = MailboxStore.getAlias();
this.setState({
alias: items,
error: false
});
}
getMailbox(id) {
if (MailboxStore.hasMailboxes()) {
const account = MailboxStore.getMailboxById(id);
MailboxStore.setCurrent(account);
let items = account.attrs.zimbraMailAlias;
if (items) {
if (!Array.isArray(items)) {
items = [items];
}
}
this.setState({
data: account,
alias: items
}); });
GlobalActions.emitEndLoading(); GlobalActions.emitEndLoading();
Utils.toggleStatusButtons('.action-info-btns', false); Utils.toggleStatusButtons('.action-info-btns', false);
} else {
return new Promise((resolve, reject) => {
Client.getAccount(id, (data) => {
return resolve(data);
}, (error) => { }, (error) => {
this.setState({ return reject(error);
notFound: true,
message: error.message
}); });
}).then((result) => {
MailboxStore.setCurrent(result);
let items = result.attrs.zimbraMailAlias;
if (items) {
if (!Array.isArray(items)) {
items = [items];
}
}
this.setState({
data: result,
alias: items
});
}).catch((error) => {
GlobalActions.emitMessage({
error: error.message,
type: error.typeError
});
}).finally(() => {
GlobalActions.emitEndLoading(); GlobalActions.emitEndLoading();
Utils.toggleStatusButtons('.action-info-btns', false); Utils.toggleStatusButtons('.action-info-btns', false);
}); });
} }
return true;
}
componentDidMount() { componentDidMount() {
EventStore.addMessageListener(this.showMessage); EventStore.addMessageListener(this.showMessage);
$('#sidebar-mailboxes').addClass('active'); $('#sidebar-mailboxes').addClass('active');
this.getMailbox(); this.getMailbox(this.props.params.id);
} }
componentWillUnmount() { componentWillUnmount() {
...@@ -77,6 +141,107 @@ export default class MailboxDetails extends React.Component { ...@@ -77,6 +141,107 @@ export default class MailboxDetails extends React.Component {
$('#sidebar-mailboxes').removeClass('active'); $('#sidebar-mailboxes').removeClass('active');
} }
onAliasSubmit(response) {
if (response.refresh) {
MailboxStore.refreshAlias(response.refresh);
}
this.multipleActions(response, this.state.data).then((result) => {
const limit = result.length;
const errors = [];
for (let index = 0; index < limit; index++) {
const res = result[index];
if (result[index].error) {
const action = (res.action === 'remove') ? 'eliminar' : 'agregar';
errors.push({
error: `Hubo un error al ${action} el alias: ${res.item}, debido a ${res.error.extra.reason}`,
type: MessageTypes.ERROR
});
}
if (res.isCompleted && res.action === 'add') {
MailboxStore.setAlias(res.item);
}
}
if (errors.length !== limit) {
errors.push({
error: 'Se han guardado los datos éxitosamente.',
type: MessageTypes.SUCCESS
});
}
this.setState({
error: errors,
alias: MailboxStore.getAlias()
});
response.reset();
});
}
multipleActions(response, account) {
const promises = [];
for (const key in response) {
if (response.hasOwnProperty(key) && key === 'add') {
const array = response[key];
const limit = array.length;
for (let index = 0; index < limit; index++) {
const res = {};
const promesa = new Promise((resolve) => {
account.addAccountAlias(array[index], (error) => {
if (error) {
res.isCompleted = false;
res.item = response[key][index];
res.action = key;
res.error = error;
} else {
res.isCompleted = true;
res.item = response[key][index];
res.action = key;
}
return resolve(res);
});
});
promises.push(promesa);
}
}
if (response.hasOwnProperty(key) && key === 'remove') {
const array = response[key];
const limit = array.length;
for (let index = 0; index < limit; index++) {
const res = {};
const promesa = new Promise((resolve) => {
account.removeAccountAlias(array[index], (error) => {
if (error) {
res.isCompleted = false;
res.item = response[key][index];
res.action = key;
res.error = error;
} else {
res.isCompleted = true;
res.item = response[key][index];
res.action = key;
}
return resolve(res);
});
});
promises.push(promesa);
}
}
}
return Promise.all(promises);
}
render() { render() {
let generalData; let generalData;
let statsData; let statsData;
...@@ -86,6 +251,18 @@ export default class MailboxDetails extends React.Component { ...@@ -86,6 +251,18 @@ export default class MailboxDetails extends React.Component {
let message; let message;
if (this.state.error) { if (this.state.error) {
if (Array.isArray(this.state.error)) {
message = this.state.error.map((err, i) => {
return (
<MessageBar
key={`new-error-${i}`}
message={err.error}
type={err.type}
autoclose={true}
/>
);
});
} else {
message = ( message = (
<MessageBar <MessageBar
message={this.state.error} message={this.state.error}
...@@ -94,6 +271,7 @@ export default class MailboxDetails extends React.Component { ...@@ -94,6 +271,7 @@ export default class MailboxDetails extends React.Component {
/> />
); );
} }
}
if (this.state.data) { if (this.state.data) {
generalData = ( generalData = (
...@@ -151,7 +329,18 @@ export default class MailboxDetails extends React.Component { ...@@ -151,7 +329,18 @@ export default class MailboxDetails extends React.Component {
const formAlias = ( const formAlias = (
<FormAliasMailbox <FormAliasMailbox
data={this.state.data} name={'alias'}
data={this.state.alias}
isEmail={true}
onDelete={(alias) => {
this.onRemoveAlias(alias);
}}
onCancel={(arrAlias) => {
this.onCancelAlias(arrAlias);
}}
onApplyChanges={(response) => {
this.onAliasSubmit(response);
}}
/> />
); );
...@@ -204,8 +393,8 @@ export default class MailboxDetails extends React.Component { ...@@ -204,8 +393,8 @@ export default class MailboxDetails extends React.Component {
return ( return (
<div> <div>
{pageInfo} {pageInfo}
{message}
<div className='content animate-panel'> <div className='content animate-panel'>
{message}
<div className='row'> <div className='row'>
<div className='col-md-6 central-content'> <div className='col-md-6 central-content'>
<Panel <Panel
......
...@@ -7,7 +7,23 @@ export default class BlockGeneralInfoMailbox extends React.Component { ...@@ -7,7 +7,23 @@ export default class BlockGeneralInfoMailbox extends React.Component {
this.date = null; this.date = null;
this.status = null; this.status = null;
this.className = null; this.className = null;
this.lastConection = 'no se ha conectado'; this.lastConection = 'No se ha conectado';
this.getMailSize = this.getMailSize.bind(this);
this.state = {};
}
getMailSize() {
this.props.data.getMailboxSize((err, bytes) => {
let currentSize = '0 MB';
if (bytes) {
currentSize = Utils.bytesToMegas(bytes);
}
this.setState({
size: currentSize
});
});
} }
componentWillMount() { componentWillMount() {
...@@ -16,24 +32,32 @@ export default class BlockGeneralInfoMailbox extends React.Component { ...@@ -16,24 +32,32 @@ export default class BlockGeneralInfoMailbox extends React.Component {
switch (this.props.data.attrs.zimbraAccountStatus) { switch (this.props.data.attrs.zimbraAccountStatus) {
case 'inactive': case 'inactive':
this.status = 'Desactivada'; this.status = 'Desactivada';
this.className = 'btn btn-md btn-default'; this.className = 'btn-default mailbox-status';
break; break;
case 'locked': case 'locked':
this.status = 'Bloqueada'; this.status = 'Bloqueada';
this.className = 'btn btn-md btn-primary2'; this.className = 'btn-primary2 mailbox-status';
break; break;
default: default:
this.status = 'Activa'; this.status = 'Activa';
this.className = 'btn btn-md btn-info'; this.className = 'btn-info mailbox-status';
break; break;
} }
if (this.props.data.attrs.zimbraLastLogonTimestamp) { if (this.props.data.attrs.zimbraLastLogonTimestamp) {
this.lastConection = Utils.dateFormatted(this.props.data.attrs.zimbraLastLogonTimestamp); this.lastConection = Utils.dateFormatted(this.props.data.attrs.zimbraLastLogonTimestamp);
} }
this.getMailSize();
} }
render() { render() {
let size = null;
if (this.state.size) {
size = this.state.size;
}
return ( return (
<div> <div>
<div className='row'> <div className='row'>
...@@ -59,7 +83,7 @@ export default class BlockGeneralInfoMailbox extends React.Component { ...@@ -59,7 +83,7 @@ export default class BlockGeneralInfoMailbox extends React.Component {
<div> <div>
<p> <p>
<span className='center-block'>Espacio Usado</span> <span className='center-block'>Espacio Usado</span>
<strong>0 Bytes</strong> <strong>{size}</strong>
</p> </p>
</div> </div>
</div> </div>
......
...@@ -112,7 +112,7 @@ MessageBar.defaultProps = { ...@@ -112,7 +112,7 @@ MessageBar.defaultProps = {
MessageBar.propTypes = { MessageBar.propTypes = {
message: React.PropTypes.string.isRequired, message: React.PropTypes.string.isRequired,
type: React.PropTypes.oneOf(['SUCCESS', 'ERROR', 'WARNING', 'INFO']), type: React.PropTypes.oneOf(['SUCCESS', 'ERROR', 'WARNING', 'INFO', 'LOCKED']),
position: React.PropTypes.oneOf(['absolute', 'fixed', 'relative', 'static', 'inherit']), position: React.PropTypes.oneOf(['absolute', 'fixed', 'relative', 'static', 'inherit']),
canClose: React.PropTypes.bool, canClose: React.PropTypes.bool,
autoclose: React.PropTypes.bool, autoclose: React.PropTypes.bool,
......
...@@ -123,7 +123,7 @@ export default class Pagination extends React.Component { ...@@ -123,7 +123,7 @@ export default class Pagination extends React.Component {
return ( return (
<div id='pagination'> <div id='pagination'>
<ul className='pagination'> <ul className='pagination pagination-sm'>
{first} {first}
{prev} {prev}
{pages} {pages}
......
//import Datalist from 'react-datalist';
import React from 'react';
import Button from './button.jsx';
import PaginateArray from '../stores/paginate_array_store.jsx';
import DataList from 'react-datalist';
import * as Utils from '../utils/utils.jsx';
import * as GlobalActions from '../action_creators/global_actions.jsx';
import Constants from '../utils/constants.jsx';
const messageType = Constants.MessageType;
export default class PanelActions extends React.Component {
constructor(props) {
super(props);
this.handleDelete = this.handleDelete.bind(this);
this.handleAddNew = this.handleAddNew.bind(this);
this.handleCancel = this.handleCancel.bind(this);
this.handleChange = this.handleChange.bind(this);
this.handleChangeLimit = this.handleChangeLimit.bind(this);
this.handleOnExport = this.handleOnExport.bind(this);
this.onSearch = this.onSearch.bind(this);
this.reset = this.reset.bind(this);
this.next = this.next.bind(this);
this.prev = this.prev.bind(this);
const limit = 10;
this.pagination = new PaginateArray(this.props.data, limit, 1);
this.add = [];
this.remove = [];
this.forAdd = [];
this.forRemove = [];
this.refresh = [];
const states = {};
states['items' + this.props.name] = this.pagination.init();
states['pagination' + this.props.name] = this.pagination.getResults();
this.state = states;
}
handleOnExport(e) {
e.preventDefault();
if (this.props.onExport) {
return this.props.onExport(this.state['items' + this.props.name]);
}
throw new Error('onExport function was not defined, onExport :' + this.props.onExport);
}
onSearch() {
const search = this.refs.search.value;
const arrayFiltered = this.props.data.filter((strArray) => {
if (strArray.match(search)) {
return strArray;
}
return false;
});
const states = {};
this.pagination.setArray(arrayFiltered);
this.pagination.reset();
states['items' + this.props.name] = this.pagination.init();
states['pagination' + this.props.name] = this.pagination.getResults();
this.setState(states);
}
prev() {
const prev = this.pagination.prevPage();
if (prev) {
const states = {};
states['items' + this.props.name] = prev;
states['pagination' + this.props.name] = this.pagination.getResults();
this.setState(states);
}
}
next() {
const next = this.pagination.nextPage();
if (next) {
const states = {};
states['items' + this.props.name] = next;
states['pagination' + this.props.name] = this.pagination.getResults();
this.setState(states);
}
}
handleDelete(e, item) {
e.preventDefault();
this.remove.push(item);
this.forRemove.push(item);
this.props.onDelete(item);
}
reset() {
this.add = [];
this.remove = [];
this.forAdd = [];
this.forRemove = [];
const states = {};
states['change' + this.props.name] = true;
this.setState(states);
}
handleAddNew(e) {
e.preventDefault();
let item = null;
Utils.validateInputRequired(this.refs).then(() => {
if (this.props.hasComboInput) {
const domain = document.querySelector('input[list=\'domain\']');
if (domain.value === '') {
GlobalActions.emitMessage({
error: 'El dominio es requerido, verifique por favor.',
typeError: messageType.ERROR
});
domain.focus();
return false;
}
item = this.refs.addInput.value + '@' + domain.value;
if (this.props.isEmail) {
const emailPattern = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i;
const test = emailPattern.test(item);
if (!test) {
GlobalActions.emitMessage({
error: 'El correo no es correcto, verifiquelo por favor.',
typeError: messageType.ERROR
});
return false;
}
}
this.add.push(item);
this.forAdd.push(item);
} else {
item = this.refs.addInput.value;
if (this.props.isEmail) {
const emailPattern = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i;
const test = emailPattern.test(item);
if (!test) {
GlobalActions.emitMessage({
error: 'El correo no es correcto, verifíquelo por favor.',
typeError: messageType.ERROR
});
this.refs.addInput.focus();
return false;
}
}
this.refs.addInput.value = '';
this.add.push(item);
this.forAdd.push(item);
}
const states = {};
states['change' + this.props.name] = true;
this.setState(states);
return true;
}).catch((error) => {
GlobalActions.emitMessage({
error: error.message,
typeError: messageType.ERROR
});
error.node.focus();
});
}
componentWillReceiveProps(nextProps) {
this.pagination.setArray(nextProps.data);
this.pagination.reset();
const states = {};
states['items' + this.props.name] = nextProps.data;
states['pagination' + this.props.name] = this.pagination.getResults();
this.setState(states);
}
handleChangeLimit() {
const limit = this.refs.countItems.value;
this.pagination.setLimit(limit);
this.pagination.reset();
const states = {};
states['items' + this.props.name] = this.pagination.init();
states['pagination' + this.props.name] = this.pagination.getResults();
this.setState(states);
}
handleChange(e, item, action) {
if (action === 'remove') {
if (e.target.checked) {
this.forRemove.push(item);
this.getOutItemFromArray(this.refresh, item);
} else {
this.getOutItemFromArray(this.forRemove, item);
this.refresh.push(item);
}
return null;
}
if (e.target.checked) {
this.forAdd.push(item);
} else {
this.getOutItemFromArray(this.forAdd, item);
}
return null;
}
getOutItemFromArray(array, item) {
const length = array.length;
if (length > 0) {
for (let i = 0; i < length; i++) {
if (item === array[i]) {
array.splice(i, 1);
return true;
}
}
}
return false;
}
handleCancel() {
this.props.onCancel(this.remove);
this.remove = [];
this.add = [];
this.forRemove = [];
this.forAdd = [];
const states = {};
states['change' + this.props.name] = true;
this.setState(states);
}
onSubmit() {
const response = {};
response.reset = this.reset;
this.refs.savebutton.setAttribute('disabled', 'disabled');
this.refs.savebutton.innerHTML = 'Aplicando Cambios...';
if (this.forAdd.length > 0) {
response.add = this.forAdd;
}
if (this.forRemove.length > 0) {
response.remove = this.forRemove;
}
if (this.refresh.length > 0) {
response.refresh = this.refresh;
}
this.props.onApplyChanges(response);
}
render() {
let rows = null;
let showName = `Agregar ${this.props.name}`;
let itemsForRemove = [];
let itemsForAdd = [];
let actionButtons = null;
let pagination = null;
let buttonExport = null;
let input = (
<div className='input-group'>
<input
type='text'
className='form-control'
placeholder={`${this.props.name}`}
ref='addInput'
data-required='true'
data-message={`${this.props.name} no pueda estar vacio, verifique por favor`}
/>
<span className='input-group-btn'>
<Button
btnAttrs={
{
className: 'btn btn-default pending_actions',
onClick: (e) => {
this.handleAddNew(e);
}
}
}
>
{showName}
</Button>
</span>
</div>
);
if (this.props.hasComboInput) {
input = (
<div className='input-group'>
<input
type='text'
ref='addInput'
className='form-control'
placeholder={this.props.name}
data-required='true'
data-message={`${this.props.name} no pueda estar vacio, verifique por favor`}
/>
<span className='input-group-addon'>
{'@'}
</span>
<DataList
list='dominio'
options={this.props.options}
placeHolder='Dominio'
/>
<span className='input-group-btn'>
<Button
btnAttrs={
{
className: 'btn btn-default pending_actions',
onClick: this.handleAddNew
}
}
>
{showName}
</Button>
</span>
</div>
);
}
if (this.state['items' + this.props.name] === 'undefined' || this.state['items' + this.props.name].length < 1) {
rows = (
<tr>
<td className='text-center'>
<strong>
{`No hay resultados para ${Utils.titleCase(this.props.name)}`}
</strong>
</td>
</tr>
);
} else {
const data = this.state['items' + this.props.name];
rows = data.map((row, index) => {
return (
<tr key={index}>
<td>
{row}
<Button
btnAttrs={
{
className: 'pull-right',
onClick: (e) => {
this.handleDelete(e, row);
}
}
}
>
<i className='fa fa-minus-circle text-danger'></i>
</Button>
</td>
</tr>
);
});
}
// make list adding / removing items
if (this.add.length > 0 || this.remove.length > 0) {
actionButtons = (
<div className='actions-buttons text-right'>
<button
className='btn btn-default pending_actions'
onClick={this.handleCancel}
>
{'Cancelar'}
</button>
<button
className='btn btn-primary pending_actions applyButtons'
onClick={() => {
this.onSubmit();
}}
ref='savebutton'
>
{'Guardar Cambios'}
</button>
</div>
);
if (this.add.length > 0) {
itemsForAdd = this.add.map((element, key) => {
return (
<label
className='list-inline listed-field'
key={`${this.props.name}labeladd${key}`}
>
<input
type='checkbox'
defaultChecked={'checked'}
data-value={element}
onChange={(e) => {
this.handleChange(e, element, 'add');
}}
/>
{element}
</label>
);
});
itemsForAdd = (
<div className='new-fields'>
<h5>Por Agregar</h5>
<div
className='new-fields-list'
>
{itemsForAdd}
</div>
</div>
);
}
if (this.remove.length > 0) {
itemsForRemove = this.remove.map((element, key) => {
return (
<label
className='list-inline listed-field'
key={`${this.props.name}labelremove${key}`}
>
<input
type='checkbox'
defaultChecked={'checked'}
data-value={element}
onChange={(e) => {
this.handleChange(e, element, 'remove');
}}
/>
{element}
</label>
);
});
itemsForRemove = (
<div className='new-fields'>
<h5>Por Eliminar</h5>
<div
className='new-fields-list'
>
{itemsForRemove}
</div>
</div>
);
}
}
if (this.state['pagination' + this.props.name]) {
pagination = this.state['pagination' + this.props.name];
}
if (this.props.hasExport && this.state['items' + this.props.name].length > 0) {
const icon = (
<div>
<i className='fa fa-download'/>
<span>{'Exportar'}</span>
</div>
);
buttonExport = (
<Button
btnAttrs={
{
className: 'btn btn-default',
onClick: (e) => {
this.handleOnExport(e);
}
}
}
>
{icon}
</Button>
);
}
return (
<div>
<div className='row'>
<div className='col-xs-6 clearfix'>
<div className='row'>
<form className='form-inline'>
<div className='col-xs-4'>
<div className='form-group'>
<label htmlFor='select-pages'>
{'Mostrar'}
<select
id='select-pages'
className='form-control input-sm margin-left'
ref='countItems'
onChange={this.handleChangeLimit}
>
<option value='10'>{'10'}</option>
<option value='25'>{'25'}</option>
<option value='50'>{'50'}</option>
<option value='100'>{'100'}</option>
</select>
</label>
</div>
</div>
<div className='col-xs-8 text-right'>
<label htmlFor='search'>
{'Buscar'}
<input
type='text'
className='form-control input-sm margin-left'
ref='search'
onKeyUp={() => {
this.onSearch();
}}
/>
</label>
</div>
</form>
</div>
<div className='col-xs-12'>
<div className='row'>
<table className='table table-striped table-bordered table-hover dataTable no-footer'>
<thead>
<tr>
<th>
{'Nombre'}
<span className='pull-right'>
<i
className='glyphicon pull-right pointer'
>
</i>
</span>
</th>
</tr>
</thead>
<tbody>
{rows}
</tbody>
</table>
</div>
</div>
<div className='col-xs-12 clearfix'>
<div className='row'>
<div className='dataTables_info pull-left'>
{buttonExport}
</div>
<div className='btn-group pull-right as-table'>
<span className='as-cell'>
{pagination}
</span>
<Button
btnAttrs={
{
className: 'btn btn-default pag-prev',
onClick: () => {
this.prev();
}
}
}
>
{'Anterior'}
</Button>
<Button
btnAttrs={
{
className: 'btn btn-default pag-next',
onClick: () => {
this.next();
}
}
}
>
{'Siguiente'}
</Button>
</div>
</div>
</div>
</div>
<div className='col-xs-6'>
<div className='col-xs-12'>
<div className='row'>
{input}
<div
className='wrap-controls'
ref='parent'
>
{itemsForAdd}
{itemsForRemove}
{actionButtons}
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}
PanelActions.propTypes = {
name: React.PropTypes.string.isRequired,
onApplyChanges: React.PropTypes.func.isRequired,
data: React.PropTypes.oneOfType([
React.PropTypes.array,
React.PropTypes.string
]),
options: React.PropTypes.array,
hasComboInput: React.PropTypes.bool,
onAdd: React.PropTypes.func,
onDelete: React.PropTypes.func,
onCancel: React.PropTypes.func,
hasExport: React.PropTypes.bool,
showNameOnButton: React.PropTypes.bool,
onExport: React.PropTypes.func,
isEmail: React.PropTypes.bool
};
PanelActions.defaultProps = {
hasComboInput: false,
hasExport: false,
showNameOnButton: true,
options: [],
isEmail: false
};
//import Datalist from 'react-datalist';
import React from 'react';
import Button from './button.jsx';
import PaginateArray from '../stores/paginate_array_store.jsx';
import DataList from 'react-datalist';
import * as Utils from '../utils/utils.jsx';
import * as GlobalActions from '../action_creators/global_actions.jsx';
import Constants from '../utils/constants.jsx';
const messageType = Constants.MessageType;
export default class PanelActions extends React.Component {
constructor(props) {
super(props);
this.handleDelete = this.handleDelete.bind(this);
this.handleAddNew = this.handleAddNew.bind(this);
this.handleCancel = this.handleCancel.bind(this);
this.handleChange = this.handleChange.bind(this);
this.handleChangeLimit = this.handleChangeLimit.bind(this);
this.handleOnExport = this.handleOnExport.bind(this);
this.onSearch = this.onSearch.bind(this);
this.reset = this.reset.bind(this);
this.next = this.next.bind(this);
this.prev = this.prev.bind(this);
const limit = 10;
this.pagination = new PaginateArray(this.props.data, limit, 1);
this.add = [];
this.remove = [];
this.forAdd = [];
this.forRemove = [];
this.refresh = [];
const states = {};
states['items' + this.props.name] = this.pagination.init();
states['pagination' + this.props.name] = this.pagination.getResults();
this.state = states;
}
handleOnExport(e) {
e.preventDefault();
if (this.props.onExport) {
return this.props.onExport(this.state['items' + this.props.name]);
}
throw new Error('onExport function was not defined, onExport :' + this.props.onExport);
}
onSearch() {
const search = this.refs.search.value;
const arrayFiltered = this.props.data.filter((strArray) => {
if (strArray.match(search)) {
return strArray;
}
return false;
});
const states = {};
this.pagination.setArray(arrayFiltered);
this.pagination.reset();
states['items' + this.props.name] = this.pagination.init();
states['pagination' + this.props.name] = this.pagination.getResults();
this.setState(states);
}
prev() {
const prev = this.pagination.prevPage();
if (prev) {
const states = {};
states['items' + this.props.name] = prev;
states['pagination' + this.props.name] = this.pagination.getResults();
this.setState(states);
}
}
next() {
const next = this.pagination.nextPage();
if (next) {
const states = {};
states['items' + this.props.name] = next;
states['pagination' + this.props.name] = this.pagination.getResults();
this.setState(states);
}
}
handleDelete(e, item) {
e.preventDefault();
this.remove.push(item);
this.forRemove.push(item);
this.props.onDelete(item);
}
reset() {
this.add = [];
this.remove = [];
this.forAdd = [];
this.forRemove = [];
const states = {};
states['change' + this.props.name] = true;
this.setState(states);
}
handleAddNew(e) {
e.preventDefault();
let item = null;
Utils.validateInputRequired(this.refs).then(() => {
if (this.props.hasComboInput) {
const domain = document.querySelector('input[list=\'domain\']');
if (domain.value === '') {
GlobalActions.emitMessage({
error: 'El dominio es requerido, verifique por favor.',
typeError: messageType.ERROR
});
domain.focus();
return false;
}
item = this.refs.addInput.value + '@' + domain.value;
if (this.props.isEmail) {
const emailPattern = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i;
const test = emailPattern.test(item);
if (!test) {
GlobalActions.emitMessage({
error: 'El correo no es correcto, verifiquelo por favor.',
typeError: messageType.ERROR
});
return false;
}
}
this.add.push(item);
this.forAdd.push(item);
} else {
item = this.refs.addInput.value;
if (this.props.isEmail) {
const emailPattern = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i;
const test = emailPattern.test(item);
if (!test) {
GlobalActions.emitMessage({
error: 'El correo no es correcto, verifíquelo por favor.',
typeError: messageType.ERROR
});
this.refs.addInput.focus();
return false;
}
}
this.refs.addInput.value = '';
this.add.push(item);
this.forAdd.push(item);
}
const states = {};
states['change' + this.props.name] = true;
this.setState(states);
return true;
}).catch((error) => {
GlobalActions.emitMessage({
error: error.message,
typeError: messageType.ERROR
});
error.node.focus();
});
}
componentWillReceiveProps(nextProps) {
this.pagination.setArray(nextProps.data);
this.pagination.reset();
const states = {};
states['items' + this.props.name] = nextProps.data;
states['pagination' + this.props.name] = this.pagination.getResults();
this.setState(states);
}
handleChangeLimit() {
const limit = this.refs.countItems.value;
this.pagination.setLimit(limit);
this.pagination.reset();
const states = {};
states['items' + this.props.name] = this.pagination.init();
states['pagination' + this.props.name] = this.pagination.getResults();
this.setState(states);
}
handleChange(e, item, action) {
if (action === 'remove') {
if (e.target.checked) {
this.forRemove.push(item);
this.getOutItemFromArray(this.refresh, item);
} else {
this.getOutItemFromArray(this.forRemove, item);
this.refresh.push(item);
}
} else if (e.target.checked) {
this.forAdd.push(item);
} else {
this.getOutItemFromArray(this.forAdd, item);
}
}
getOutItemFromArray(array, item) {
const length = array.length;
if (length > 0) {
for (let i = 0; i < length; i++) {
if (item === array[i]) {
array.splice(i, 1);
return true;
}
}
}
return false;
}
handleCancel() {
this.props.onCancel(this.remove);
this.remove = [];
this.add = [];
this.forRemove = [];
this.forAdd = [];
const states = {};
states['change' + this.props.name] = true;
this.setState(states);
}
onSubmit() {
const response = {};
response.reset = this.reset;
this.refs.savebutton.setAttribute('disabled', 'disabled');
this.refs.savebutton.innerHTML = 'Aplicando Cambios...';
if (this.forAdd.length > 0) {
response.add = this.forAdd;
}
if (this.forRemove.length > 0) {
response.remove = this.forRemove;
}
if (this.refresh.length > 0) {
response.refresh = this.refresh;
}
this.props.onApplyChanges(response);
}
render() {
let rows = null;
let showName = `Agregar ${this.props.name}`;
let itemsForRemove = [];
let itemsForAdd = [];
let actionButtons = null;
let pagination = null;
let buttonExport = null;
let input = (
<div className='input-group'>
<input
type='text'
className='form-control'
placeholder={`${this.props.name}`}
ref='addInput'
data-required='true'
data-message={`${this.props.name} no pueda estar vacio, verifique por favor`}
/>
<span className='input-group-btn'>
<Button
btnAttrs={
{
className: 'btn btn-default pending_actions',
onClick: (e) => {
this.handleAddNew(e);
}
}
}
>
{showName}
</Button>
</span>
</div>
);
if (this.props.hasComboInput) {
input = (
<div className='input-group'>
<input
type='text'
ref='addInput'
className='form-control'
placeholder={this.props.name}
data-required='true'
data-message={`${this.props.name} no pueda estar vacio, verifique por favor`}
/>
<span className='input-group-addon'>
{'@'}
</span>
<DataList
list='dominio'
options={this.props.options}
placeHolder='Dominio'
/>
<span className='input-group-btn'>
<Button
btnAttrs={
{
className: 'btn btn-default pending_actions',
onClick: this.handleAddNew
}
}
>
{showName}
</Button>
</span>
</div>
);
}
if (this.state['items' + this.props.name] === 'undefined' || this.state['items' + this.props.name].length < 1) {
rows = (
<tr>
<td className='text-center'>
<strong>
{`No hay resultados para ${Utils.titleCase(this.props.name)}`}
</strong>
</td>
</tr>
);
} else {
const data = this.state['items' + this.props.name];
rows = data.map((row, index) => {
return (
<tr key={index}>
<td>
{row}
<Button
btnAttrs={
{
className: 'pull-right',
onClick: (e) => {
this.handleDelete(e, row);
}
}
}
>
<i className='fa fa-minus-circle text-danger'></i>
</Button>
</td>
</tr>
);
});
}
// make list adding / removing items
if (this.add.length > 0 || this.remove.length > 0) {
actionButtons = (
<div className='actions-buttons text-right'>
<button
className='btn btn-default pending_actions'
onClick={this.handleCancel}
>
{'Cancelar'}
</button>
<button
className='btn btn-primary pending_actions applyButtons'
onClick={() => {
this.onSubmit();
}}
ref='savebutton'
>
{'Guardar Cambios'}
</button>
</div>
);
if (this.add.length > 0) {
itemsForAdd = this.add.map((element, key) => {
return (
<label
className='list-inline listed-field'
key={`${this.props.name}labeladd${key}`}
>
<input
type='checkbox'
defaultChecked={'checked'}
data-value={element}
onChange={(e) => {
this.handleChange(e, element, 'add');
}}
/>
{element}
</label>
);
});
itemsForAdd = (
<div className='new-fields'>
<h5>Por Agregar</h5>
<div
className='new-fields-list'
>
{itemsForAdd}
</div>
</div>
);
}
if (this.remove.length > 0) {
itemsForRemove = this.remove.map((element, key) => {
return (
<label
className='list-inline listed-field'
key={`${this.props.name}labelremove${key}`}
>
<input
type='checkbox'
defaultChecked={'checked'}
data-value={element}
onChange={(e) => {
this.handleChange(e, element, 'remove');
}}
/>
{element}
</label>
);
});
itemsForRemove = (
<div className='new-fields'>
<h5>Por Eliminar</h5>
<div
className='new-fields-list'
>
{itemsForRemove}
</div>
</div>
);
}
}
if (this.state['pagination' + this.props.name]) {
pagination = this.state['pagination' + this.props.name];
}
if (this.props.hasExport && this.state['items' + this.props.name].length > 0) {
const icon = (
<div>
<i className='fa fa-download'/>
<span>{'Exportar'}</span>
</div>
);
buttonExport = (
<Button
btnAttrs={
{
className: 'btn btn-default',
onClick: (e) => {
this.handleOnExport(e);
}
}
}
>
{icon}
</Button>
);
}
return (
<div>
<div className='row'>
<div className='col-xs-6 clearfix'>
<div className='row'>
<form className='form-inline'>
<div className='col-xs-4'>
<div className='form-group'>
<label htmlFor='select-pages'>
{'Mostrar'}
<select
id='select-pages'
className='form-control input-sm margin-left'
ref='countItems'
onChange={this.handleChangeLimit}
>
<option value='10'>{'10'}</option>
<option value='25'>{'25'}</option>
<option value='50'>{'50'}</option>
<option value='100'>{'100'}</option>
</select>
</label>
</div>
</div>
<div className='col-xs-8 text-right'>
<label htmlFor='search'>
{'Buscar'}
<input
type='text'
className='form-control input-sm margin-left'
ref='search'
onKeyUp={() => {
this.onSearch();
}}
/>
</label>
</div>
</form>
</div>
<div className='col-xs-12'>
<div className='row'>
<table className='table table-striped table-bordered table-hover dataTable no-footer'>
<thead>
<tr>
<th>
{'Nombre'}
<span className='pull-right'>
<i
className='glyphicon pull-right pointer'
>
</i>
</span>
</th>
</tr>
</thead>
<tbody>
{rows}
</tbody>
</table>
</div>
</div>
<div className='col-xs-12 clearfix'>
<div className='row'>
<div className='dataTables_info pull-left'>
{buttonExport}
</div>
<div className='btn-group pull-right as-table'>
<span className='as-cell'>
{pagination}
</span>
<Button
btnAttrs={
{
className: 'btn btn-default pag-prev',
onClick: () => {
this.prev();
}
}
}
>
{'Anterior'}
</Button>
<Button
btnAttrs={
{
className: 'btn btn-default pag-next',
onClick: () => {
this.next();
}
}
}
>
{'Siguiente'}
</Button>
</div>
</div>
</div>
</div>
<div className='col-xs-6'>
<div className='col-xs-12'>
<div className='row'>
{input}
<div
className='wrap-controls'
ref='parent'
>
{itemsForAdd}
{itemsForRemove}
{actionButtons}
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}
PanelActions.propTypes = {
name: React.PropTypes.string.isRequired,
onApplyChanges: React.PropTypes.func.isRequired,
data: React.PropTypes.oneOfType([
React.PropTypes.array,
React.PropTypes.string
]),
options: React.PropTypes.array,
hasComboInput: React.PropTypes.bool,
onAdd: React.PropTypes.func,
onDelete: React.PropTypes.func,
onCancel: React.PropTypes.func,
hasExport: React.PropTypes.bool,
showNameOnButton: React.PropTypes.bool,
onExport: React.PropTypes.func,
isEmail: React.PropTypes.bool
};
PanelActions.defaultProps = {
hasComboInput: false,
hasExport: false,
showNameOnButton: true,
options: [],
isEmail: false
};
{ {
"debug": true, "debug": false,
"zimbraUrl": "http://zimbra.zboxapp.dev:8000/service/admin/soap", "zimbraUrl": "http://zimbra.zboxapp.dev:8000/service/admin/soap",
"zimbraProxy": "https://zimbra.zboxapp.dev:7071", "zimbraProxy": "https://zimbra.zboxapp.dev:7071",
"dnsApiUrl": "http://zimbra.zboxapp.dev:3000", "dnsApiUrl": "http://zimbra.zboxapp.dev:3000",
......
...@@ -20,6 +20,8 @@ import Mailboxes from './components/mailbox/mailbox.jsx'; ...@@ -20,6 +20,8 @@ import Mailboxes from './components/mailbox/mailbox.jsx';
import MailboxDetails from './components/mailbox/mailbox_details.jsx'; import MailboxDetails from './components/mailbox/mailbox_details.jsx';
import CreateMailBox from './components/mailbox/create_mailbox.jsx'; import CreateMailBox from './components/mailbox/create_mailbox.jsx';
import EditMailBox from './components/mailbox/edit_mailbox.jsx'; import EditMailBox from './components/mailbox/edit_mailbox.jsx';
import DistributionLists from './components/distribution/distribution_lists.jsx';
import EditDistributionList from './components/distribution/edit_distribution_lists.jsx';
import * as Client from './utils/client.jsx'; import * as Client from './utils/client.jsx';
import * as Utils from './utils/utils.jsx'; import * as Utils from './utils/utils.jsx';
...@@ -77,12 +79,7 @@ function onPreLoggedIn(nextState, replace, callback) { ...@@ -77,12 +79,7 @@ function onPreLoggedIn(nextState, replace, callback) {
global.window.Zimbra = ZimbraStore.getCurrent(); global.window.Zimbra = ZimbraStore.getCurrent();
} }
const cos = ZimbraStore.getAllCos(); Client.getAllCos(
if (cos) {
return callback();
}
return Client.getAllCos(
(cosData) => { (cosData) => {
ZimbraStore.setAllCos(cosData); ZimbraStore.setAllCos(cosData);
return callback(); return callback();
...@@ -146,6 +143,14 @@ function renderRootComponent() { ...@@ -146,6 +143,14 @@ function renderRootComponent() {
path='domains/:domain_id/mailboxes' path='domains/:domain_id/mailboxes'
component={Mailboxes} component={Mailboxes}
/> />
<Route
path='domains/:domain_id/distribution_lists/:id'
component={DistributionLists}
/>
<Route
path='domains/:domain_id/distribution_lists/:id/edit'
component={EditDistributionList}
/>
<Route <Route
path='companies' path='companies'
......
...@@ -18,4 +18,9 @@ ...@@ -18,4 +18,9 @@
background: $bg-warning-color; background: $bg-warning-color;
color: $white; color: $white;
} }
.flash-locked {
background: $color-violet;
color: $white;
}
} }
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
@import 'lists'; @import 'lists';
@import 'loader'; @import 'loader';
@import 'modal'; @import 'modal';
@import 'panel_add';
@import 'panels'; @import 'panels';
@import 'progress_bar'; @import 'progress_bar';
@import 'tabs'; @import 'tabs';
......
.new-fields {
border-top: 1px solid $color-new-fields;
margin-top: 30px;
h5 {
margin: 5px 0;
}
.new-fields-list {
.listed-field {
margin: 8px 0 0 10px;
input {
margin-right: 5px;
}
}
}
}
.actions-buttons {
margin-top: 20px;
a {
margin-left: 5px;
&:first-child {
margin-left: 0;
}
}
}
.as-table {
display: table;
.as-cell {
display: table-cell;
padding-right: 10px;
vertical-align: middle;
}
}
.margin-left {
margin-left: 5px;
}
...@@ -614,7 +614,7 @@ a { ...@@ -614,7 +614,7 @@ a {
float: left; float: left;
height: 52px; height: 52px;
padding: 0; padding: 0;
width: 80%; width: 70%;
.form-control { .form-control {
background: none repeat scroll 0 0 $transparent; background: none repeat scroll 0 0 $transparent;
...@@ -1272,7 +1272,7 @@ label { ...@@ -1272,7 +1272,7 @@ label {
.panel-body { .panel-body {
padding: 0; padding: 0;
.btn { .btn:not(.pending_actions) {
margin: 0; margin: 0;
} }
} }
......
...@@ -54,3 +54,8 @@ ...@@ -54,3 +54,8 @@
} }
} }
} }
.domain-name {
font-size: 22px;
font-weight: 600;
}
.noplan {
background: $black;
}
.account-info {
p {
margin-bottom: 3px;
}
}
.mailbox-status {
border: solid 1px;
border-radius: 2px;
color: $white;
display: inline-block;
padding: 5px;
text-align: center;
width: 100px;
}
.m-r {
margin-right: 5px;
}
.label-locked {
background: $color-violet;
}
...@@ -2,3 +2,4 @@ ...@@ -2,3 +2,4 @@
@import 'login'; @import 'login';
@import 'domain'; @import 'domain';
@import 'companies'; @import 'companies';
@import 'mailbox';
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
// Dependancies // Dependancies
@import '~bootstrap/dist/css/bootstrap.css'; @import '~bootstrap/dist/css/bootstrap.css';
@import '~jasny-bootstrap/dist/css/jasny-bootstrap.css'; @import '~jasny-bootstrap/dist/css/jasny-bootstrap.css';
@import '~perfect-scrollbar/dist/css/perfect-scrollbar.css';
@import '~font-awesome/css/font-awesome.css'; @import '~font-awesome/css/font-awesome.css';
@import '~nprogress/nprogress.css'; @import '~nprogress/nprogress.css';
@import '~toastr/build/toastr.css'; @import '~toastr/build/toastr.css';
......
...@@ -84,3 +84,6 @@ $bg-border-color: #63a758; ...@@ -84,3 +84,6 @@ $bg-border-color: #63a758;
$account-link-color: #337ab7; $account-link-color: #337ab7;
//Panel add
$color-new-fields: #e4e5e7;
...@@ -10,6 +10,8 @@ class DomainStoreClass extends EventEmitter { ...@@ -10,6 +10,8 @@ class DomainStoreClass extends EventEmitter {
constructor() { constructor() {
super(); super();
this.current = null; this.current = null;
this.distributionListOwners = null;
this.distributionListMembers = null;
} }
getCurrent() { getCurrent() {
...@@ -129,6 +131,26 @@ class DomainStoreClass extends EventEmitter { ...@@ -129,6 +131,26 @@ class DomainStoreClass extends EventEmitter {
return lists; return lists;
} }
getDistributionListById(listId, domain) {
if (this.current !== domain) {
this.setCurrent(domain);
}
const distributionLists = this.current.lists;
if (!distributionLists) {
return null;
}
for (const id in distributionLists) {
if (distributionLists.hasOwnProperty(id) && id === listId) {
return distributionLists[id];
}
}
return false;
}
setDistibutionLists(domain, listsArray) { setDistibutionLists(domain, listsArray) {
if (this.current !== domain) { if (this.current !== domain) {
this.setCurrent(domain); this.setCurrent(domain);
...@@ -151,6 +173,74 @@ class DomainStoreClass extends EventEmitter { ...@@ -151,6 +173,74 @@ class DomainStoreClass extends EventEmitter {
this.emitDistributionListsChange(); this.emitDistributionListsChange();
} }
getMembers() {
if (this.distributionListMembers) {
return this.distributionListMembers;
}
return null;
}
setMembers(members) {
this.distributionListMembers = members;
}
addMember(member) {
if (this.distributionListMembers && Array.isArray(this.distributionListMembers)) {
this.distributionListMembers.push(member);
}
}
removeMember(member) {
if (this.distributionListMembers && Array.isArray(this.distributionListMembers)) {
const members = this.distributionListMembers;
const length = members.length;
for (let i = 0; i < length; i++) {
if (members[i] === member) {
members.splice(i, 1);
return true;
}
}
}
return false;
}
getOwners() {
if (this.distributionListOwners) {
return this.distributionListOwners;
}
return null;
}
setOwners(owners) {
this.distributionListOwners = owners;
}
addOwners(owner) {
if (this.distributionListOwners && Array.isArray(this.distributionListOwners)) {
this.distributionListOwners.push(owner);
}
}
removeOwner(owner) {
if (this.distributionListOwners && Array.isArray(this.distributionListOwners)) {
const owners = this.distributionListOwners;
const length = owners.length;
for (let i = 0; i < length; i++) {
if (owners[i] === owner) {
owners.splice(i, 1);
return true;
}
}
}
return false;
}
removeDistributionList(listId) { removeDistributionList(listId) {
if (this.current.lists) { if (this.current.lists) {
Reflect.deleteProperty(this.current.lists, listId); Reflect.deleteProperty(this.current.lists, listId);
......
// Copyright (c) 2016 ZBox, Spa. All Rights Reserved.
// See LICENSE.txt for license information.
import EventEmitter from 'events';
let mailboxesArray = null;
class MailboxStoreClass extends EventEmitter {
constructor() {
super();
this.current = null;
}
getMailboxById(id) {
if (mailboxesArray) {
const accounts = mailboxesArray.account;
const size = accounts.length;
for (let i = 0; i < size; i++) {
if (id === accounts[i].id) {
return accounts[i];
}
}
}
return false;
}
setMailbox(mailbox) {
if (mailboxesArray) {
const currentTotal = mailboxesArray.account.push(mailbox);
if (currentTotal > mailboxesArray.total) {
mailboxesArray.total = currentTotal;
}
}
}
setCurrent(account) {
this.current = account;
}
getCurrent() {
return this.current;
}
hasMailboxes() {
if (mailboxesArray) {
return true;
}
return false;
}
getMailboxes() {
return mailboxesArray;
}
setMailboxes(mailboxes) {
mailboxesArray = mailboxes;
}
changeAccount(newAccount) {
if (mailboxesArray) {
const accounts = mailboxesArray.account;
const size = accounts.length;
const id = newAccount.id;
for (let i = 0; i < size; i++) {
if (id === accounts[i].id) {
accounts[i] = newAccount;
return accounts[i];
}
}
}
return false;
}
removeAccount(account) {
if (mailboxesArray) {
const accounts = mailboxesArray.account;
const size = accounts.length;
const id = account.id;
for (let i = 0; i < size; i++) {
if (id === accounts[i].id) {
accounts.splice(i, 1);
if (mailboxesArray.total > 0) {
mailboxesArray.total = mailboxesArray.total - 1;
}
this.setMailboxes(mailboxesArray);
return true;
}
}
}
return false;
}
getAlias() {
let zimbraAlias;
if (this.current) {
if (this.current.attrs.zimbraMailAlias) {
if (!Array.isArray(this.current.attrs.zimbraMailAlias)) {
this.current.attrs.zimbraMailAlias = [this.current.attrs.zimbraMailAlias];
}
zimbraAlias = this.current.attrs.zimbraMailAlias;
} else {
this.current.attrs.zimbraMailAlias = [];
zimbraAlias = this.current.attrs.zimbraMailAlias;
}
return zimbraAlias;
}
return false;
}
setAlias(item) {
if (this.current) {
const alias = this.getAlias();
if (alias) {
alias.push(item);
}
}
}
removeAlias(alias) {
if (this.current) {
const aliasArray = this.getAlias();
if (aliasArray) {
const limit = aliasArray.length;
for (let i = 0; i < limit; i++) {
if (alias === aliasArray[i]) {
aliasArray.splice(i, 1);
return true;
}
}
}
}
return false;
}
refreshAlias(array) {
if (this.current) {
const alias = this.getAlias();
if (alias) {
Array.prototype.push.apply(alias, array);
}
return true;
}
return false;
}
}
const MailboxStore = new MailboxStoreClass();
export {MailboxStore as default};
// Copyright (c) 2016 ZBox, Spa. All Rights Reserved.
// See LICENSE.txt for license information.
class PaginateArrayStoreClass {
constructor(array, limit, page) {
this.getLength = this.getLength.bind(this);
this.paged = page || 1;
this.currentArray = array || [];
this.results = null;
this.limit = limit;
this.offset = ((this.paged - 1) * this.limit);
this.totalPage = Math.ceil(this.getLength() / this.limit);
}
init() {
return this.currentArray.slice(this.offset, (this.paged * this.limit));
}
nextPage() {
if ((this.paged + 1) > this.totalPage) {
return false;
}
this.paged += 1;
this.offset = ((this.paged - 1) * this.limit);
return this.currentArray.slice(this.offset, (this.paged * this.limit));
}
getLength() {
return this.currentArray.length;
}
prevPage() {
if ((this.paged - 1) < 1) {
return false;
}
this.paged -= 1;
this.offset = ((this.paged - 1) * this.limit);
return this.currentArray.slice(this.offset, (this.paged * this.limit));
}
setLimit(limit) {
this.limit = limit;
}
setArray(array) {
this.currentArray = array;
}
getResults() {
let pagination;
if (this.currentArray.length < 1) {
pagination = '0 resultados';
} else {
const start = (this.currentArray.length < 1) ? 0 : (this.offset + 1);
const end = ((this.paged * this.limit) > this.getLength()) ? this.getLength() : (this.paged * this.limit);
pagination = start + ' al ' + end + ' de ' + this.getLength();
}
return pagination;
}
reset() {
this.paged = 1;
this.offset = ((this.paged - 1) * this.limit);
this.resetTotalPage();
return this.init();
}
resetTotalPage() {
this.totalPage = Math.ceil(this.getLength() / this.limit);
}
}
//const PaginateArrayStore = new PaginateArrayStoreClass();
export {PaginateArrayStoreClass as default};
...@@ -556,3 +556,60 @@ export function getAllCos(success, error) { ...@@ -556,3 +556,60 @@ export function getAllCos(success, error) {
} }
); );
} }
export function getDistributionList(id, success, error) {
initZimbra().then(
(zimbra) => {
zimbra.getDistributionList(id, (err, data) => {
if (err) {
const e = handleError('getDistributionList', err);
return error(e);
}
return success(data);
});
},
(err) => {
const e = handleError('getDistributionList', err);
return error(e);
}
);
}
export function modifyDistributionList(id, attrs, success, error) {
initZimbra().then(
(zimbra) => {
zimbra.modifyDistributionList(id, attrs, (err, data) => {
if (err) {
const e = handleError('modifyDistributionList', err);
return error(e);
}
return success(data);
});
},
(err) => {
const e = handleError('modifyDistributionList', err);
return error(e);
}
);
}
export function renameAccount(account, success, error) {
initZimbra().then(
(zimbra) => {
zimbra.renameAccount(account, (err, data) => {
if (err) {
const e = handleError('renameAccount', err);
return error(e);
}
return success(data);
});
},
(err) => {
const e = handleError('renameAccount', err);
return error(e);
}
);
}
...@@ -21,6 +21,7 @@ export default { ...@@ -21,6 +21,7 @@ export default {
EventTypes: keyMirror({ EventTypes: keyMirror({
DOMAIN_ADMINS_CHANGE_EVENT: null, DOMAIN_ADMINS_CHANGE_EVENT: null,
DOMAIN_DLS_CHANGE_EVENT: null, DOMAIN_DLS_CHANGE_EVENT: null,
ACCOUNT_CHANGE_EVENT: null,
START_LOADING_EVENT: null, START_LOADING_EVENT: null,
END_LOADING_EVENT: null, END_LOADING_EVENT: null,
USER_CHANGE_EVENT: null, USER_CHANGE_EVENT: null,
...@@ -32,7 +33,8 @@ export default { ...@@ -32,7 +33,8 @@ export default {
SUCCESS: null, SUCCESS: null,
WARNING: null, WARNING: null,
ERROR: null, ERROR: null,
INFO: null INFO: null,
LOCKED: null
}), }),
ZimbraCodes: { ZimbraCodes: {
......
...@@ -311,3 +311,236 @@ export function getEnabledPlansByCosId(cosArray) { ...@@ -311,3 +311,236 @@ export function getEnabledPlansByCosId(cosArray) {
return plans; return plans;
} }
export function getMembers(members, label) {
let tag = label;
if (Array.isArray(members)) {
if (members.length === 1) {
tag = tag.slice(0, -1);
}
return members.length + ' ' + tag;
}
throw new Error('El tipo de members no es un arreglo : ' + typeof members);
}
export function bytesToMegas(bytes) {
let size = '0 MB';
if (bytes && typeof bytes === 'number') {
size = bytes;
const mb = 1024;
size = ((size / mb) / mb).toFixed(2) + 'MB';
}
return size;
}
export function getDomainFromString(string, otherwise) {
let domain = otherwise || 'Dominio Invalido';
if (typeof string === 'string' && string.lastIndexOf('@') > -1) {
domain = string.split('@');
domain = domain.pop();
}
return domain;
}
export function exportAsCSV(data, title, hasLabel) {
const info = (typeof data === 'object') ? data : JSON.parse(data);
let CSV = '';
CSV += title + '\r\n\n';
if (hasLabel) {
let row = '';
for (const index in info[0]) {
if (info[0].hasOwnProperty(index)) {
row += index + ',';
}
}
row = row.slice(0, row.length - 1);
CSV += row + '\r\n';
}
for (var i = 0; i < info.length; i++) {
let row = '';
for (var index in info[i]) {
if (info[i].hasOwnProperty(index)) {
row += '\'' + info[i][index] + '\',';
}
}
row = row.slice(0, -1);
CSV += row + '\r\n';
}
if (CSV === '') {
return;
}
const fileName = title.replace(/ /g, '_') + new Date().getTime();
const uri = 'data:text/csv;charset=utf-8,' + encodeURIComponent(CSV);
if (isSafari()) {
const time = 500;
var close = window.open('data:attachment/csv;charset=utf-8,' + encodeURIComponent(CSV), '_blank', 'width=1,height=1');
setTimeout(() => {
close.close();
}, time);
return;
}
const link = document.createElement('a');
link.href = uri;
link.style = 'visibility:hidden';
link.download = fileName + '.csv';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
export function isChrome() {
if (navigator.userAgent.indexOf('Chrome') > -1) {
return true;
}
return false;
}
export function isSafari() {
if (navigator.userAgent.indexOf('Safari') !== -1 && navigator.userAgent.indexOf('Chrome') === -1) {
return true;
}
return false;
}
export function isIosChrome() {
// https://developer.chrome.com/multidevice/user-agent
return navigator.userAgent.indexOf('CriOS') !== -1;
}
export function isFirefox() {
return navigator && navigator.userAgent && navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
}
export function isIE() {
if (window.navigator && window.navigator.userAgent) {
var ua = window.navigator.userAgent;
return ua.indexOf('Trident/7.0') > 0 || ua.indexOf('Trident/6.0') > 0;
}
return false;
}
export function isEdge() {
return window.navigator && navigator.userAgent && navigator.userAgent.toLowerCase().indexOf('edge') > -1;
}
export function addOrRemoveAlias(account, params) {
let promises = [];
for (const label in params) {
if (params.hasOwnProperty(label)) {
if (label === 'add') {
const length = params[label].length;
for (let i = 0; i < length; i++) {
let mypromise = new Promise((resolve) => {
account.addAccountAlias(params[label][i], (response) => {
if (response) {
resolve({
resolved: false,
err: response,
item: params[label][i],
action: 'add'
});
} else {
resolve({
resolved: true,
action: 'add'
});
}
});
});
promises.push(mypromise);
}
}
if (label === 'remove') {
const length = params[label].length;
for (let i = 0; i < length; i++) {
let mypromise = new Promise((resolve) => {
account.removeAccountAlias(params[label][i], (response) => {
if (response) {
resolve({
resolved: false,
err: response,
item: params[label][i],
action: 'remove'
});
} else {
resolve({
resolved: true,
action: 'remove'
});
}
});
});
promises.push(mypromise);
}
}
}
}
return Promise.all(promises);
}
export function getEnabledPlansObjectByCos(cosArray, cosID) {
const configPlans = global.window.manager_config.plans;
const plans = {};
const id = cosID || false;
cosArray.forEach((cos) => {
const key = cos.name;
if (configPlans.hasOwnProperty(key) && configPlans[key]) {
if (id) {
if (cos.id === id) {
plans.name = key;
plans.id = cos.id;
plans.attrs = cos.attrs;
}
} else {
plans[key] = {};
plans[key].id = cos.id;
plans[key].attrs = cos.attrs;
}
}
});
return plans;
}
export function getOwners(owners) {
if (Array.isArray(owners)) {
const limit = owners.length;
const ownersArray = [];
for (let i = 0; i < limit; i++) {
ownersArray.push(owners[i].name);
}
return ownersArray;
}
throw Error('Owners array no es un arreglo :' + typeof owners);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment