Commit 2f15a532 authored by Patricio Bruna's avatar Patricio Bruna

Merge pull request #75 from ZBoxApp/issues_resolved

Esperemos que no explote
parents c82ac91a 58b41f50
module.exports = {"main":{"js":"/244695bundle.js"}} module.exports = {"main":{"js":"/887398bundle.js"}}
\ No newline at end of file \ No newline at end of file
...@@ -20,8 +20,8 @@ export default class AntiSpam extends React.Component { ...@@ -20,8 +20,8 @@ export default class AntiSpam extends React.Component {
this.handleSave = this.handleSave.bind(this); this.handleSave = this.handleSave.bind(this);
this.alterDomain = this.alterDomain.bind(this); this.alterDomain = this.alterDomain.bind(this);
this.domain = DomainStore.getCurrent(); this.domain = DomainStore.getCurrent();
this.blackList = null; this.blackList = [];
this.whiteList = null; this.whiteList = [];
if (this.domain.attrs.amavisBlacklistSender) { if (this.domain.attrs.amavisBlacklistSender) {
this.blackList = Array.isArray(this.domain.attrs.amavisBlacklistSender) ? this.domain.attrs.amavisBlacklistSender : this.domain.attrs.amavisBlacklistSender.trim().split(' '); this.blackList = Array.isArray(this.domain.attrs.amavisBlacklistSender) ? this.domain.attrs.amavisBlacklistSender : this.domain.attrs.amavisBlacklistSender.trim().split(' ');
...@@ -39,11 +39,11 @@ export default class AntiSpam extends React.Component { ...@@ -39,11 +39,11 @@ export default class AntiSpam extends React.Component {
switch (action) { switch (action) {
case 'black': case 'black':
this.searchItemToRemove(this.blackList, item); this.searchItemToRemove(this.blackList, item);
attrs.amavisBlacklistSender = this.blackList; attrs.amavisBlacklistSender = this.blackList.length > 0 ? this.blackList : null;
break; break;
case 'white': case 'white':
this.searchItemToRemove(this.whiteList, item); this.searchItemToRemove(this.whiteList, item);
attrs.amavisWhitelistSender = this.whiteList; attrs.amavisWhitelistSender = this.whiteList.length > 0 ? this.whiteList : null;
break; break;
} }
......
...@@ -111,6 +111,7 @@ export default class DomainMailboxPlans extends React.Component { ...@@ -111,6 +111,7 @@ export default class DomainMailboxPlans extends React.Component {
); );
} }
} else { } else {
console.log(totalLimit);
totalLimit += plan.limit; totalLimit += plan.limit;
} }
......
...@@ -17,6 +17,7 @@ import * as Client from '../../utils/client.jsx'; ...@@ -17,6 +17,7 @@ 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'; import Constants from '../../utils/constants.jsx';
import UserStore from '../../stores/user_store.jsx';
const QueryOptions = Constants.QueryOptions; const QueryOptions = Constants.QueryOptions;
const messageType = Constants.MessageType; const messageType = Constants.MessageType;
...@@ -28,12 +29,14 @@ export default class Domains extends React.Component { ...@@ -28,12 +29,14 @@ export default class Domains extends React.Component {
this.getDomains = this.getDomains.bind(this); this.getDomains = this.getDomains.bind(this);
const page = parseInt(this.props.location.query.page, 10) || 1; const page = parseInt(this.props.location.query.page, 10) || 1;
this.isGlobalAdmin = UserStore.isGlobalAdmin();
this.state = { this.state = {
page, page,
offset: ((page - 1) * QueryOptions.DEFAULT_LIMIT) offset: ((page - 1) * QueryOptions.DEFAULT_LIMIT)
}; };
} }
getDomains() { getDomains() {
const self = this; const self = this;
Client.getAllDomains( Client.getAllDomains(
...@@ -72,6 +75,7 @@ export default class Domains extends React.Component { ...@@ -72,6 +75,7 @@ export default class Domains extends React.Component {
} }
); );
} }
getPlans(domains) { getPlans(domains) {
const names = domains.map((d) => { const names = domains.map((d) => {
return d.name; return d.name;
...@@ -110,6 +114,7 @@ export default class Domains extends React.Component { ...@@ -110,6 +114,7 @@ export default class Domains extends React.Component {
$('#sidebar-domains').addClass('active'); $('#sidebar-domains').addClass('active');
this.getDomains(); this.getDomains();
} }
componentWillUnmount() { componentWillUnmount() {
$('#sidebar-domains').removeClass('active'); $('#sidebar-domains').removeClass('active');
} }
...@@ -117,6 +122,7 @@ export default class Domains extends React.Component { ...@@ -117,6 +122,7 @@ export default class Domains extends React.Component {
render() { render() {
const error = this.state.error; const error = this.state.error;
let message; let message;
let addDomainButton = null;
if (error) { if (error) {
message = ( message = (
<MessageBar <MessageBar
...@@ -127,15 +133,17 @@ export default class Domains extends React.Component { ...@@ -127,15 +133,17 @@ export default class Domains extends React.Component {
); );
} }
const addDomainButton = [{ if (this.isGlobalAdmin) {
label: 'Agregar Dominio', addDomainButton = [{
props: { label: 'Agregar Dominio',
className: 'btn btn-success', props: {
onClick: (e) => { className: 'btn btn-success',
Utils.handleLink(e, '/domains/new'); onClick: (e) => {
Utils.handleLink(e, '/domains/new');
}
} }
} }];
}]; }
let tableResults; let tableResults;
if (this.state.data) { if (this.state.data) {
...@@ -233,7 +241,7 @@ export default class Domains extends React.Component { ...@@ -233,7 +241,7 @@ export default class Domains extends React.Component {
<thead> <thead>
<tr> <tr>
<th>{'Nombre'}</th> <th>{'Nombre'}</th>
<th className='text-center'>{'Casillas Usadas'}</th> <th className='text-center'>{'Casillas Compradas'}</th>
<th className='text-center'>{'Descripción'}</th> <th className='text-center'>{'Descripción'}</th>
<th className='text-center'>{'Estado'}</th> <th className='text-center'>{'Estado'}</th>
</tr> </tr>
......
...@@ -7,6 +7,7 @@ import ReactDOM from 'react-dom'; ...@@ -7,6 +7,7 @@ import ReactDOM from 'react-dom';
import * as GlobalActions from '../action_creators/global_actions.jsx'; import * as GlobalActions from '../action_creators/global_actions.jsx';
import {browserHistory, Link} from 'react-router'; import {browserHistory, Link} from 'react-router';
import * as Utils from '../utils/utils.jsx';
import logo from '../images/logo.png'; import logo from '../images/logo.png';
export default class Header extends React.Component { export default class Header extends React.Component {
...@@ -15,6 +16,7 @@ export default class Header extends React.Component { ...@@ -15,6 +16,7 @@ export default class Header extends React.Component {
this.handleSearch = this.handleSearch.bind(this); this.handleSearch = this.handleSearch.bind(this);
this.toggleSidebar = this.toggleSidebar.bind(this); this.toggleSidebar = this.toggleSidebar.bind(this);
} }
handleSearch(e) { handleSearch(e) {
e.preventDefault(); e.preventDefault();
const search = ReactDOM.findDOMNode(this.refs.query); const search = ReactDOM.findDOMNode(this.refs.query);
...@@ -22,11 +24,14 @@ export default class Header extends React.Component { ...@@ -22,11 +24,14 @@ export default class Header extends React.Component {
const utf8 = ReactDOM.findDOMNode(this.refs.utf8).value.trim(); const utf8 = ReactDOM.findDOMNode(this.refs.utf8).value.trim();
search.value = ''; search.value = '';
GlobalActions.emitStartLoading(); GlobalActions.emitStartLoading();
browserHistory.push(`search/global?utf8=${utf8}&query=${encodeURIComponent(term)}`); Utils.handleLink(e, `/search/${encodeURIComponent(term)}`);
//browserHistory.push(`search/?utf8=${utf8}&query=${encodeURIComponent(term)}`);
} }
toggleSidebar() { toggleSidebar() {
$('body').toggleClass('hide-sidebar').toggleClass('show-sidebar'); $('body').toggleClass('hide-sidebar').toggleClass('show-sidebar');
} }
render() { render() {
return ( return (
<div id='header'> <div id='header'>
......
...@@ -34,7 +34,7 @@ export default class Login extends React.Component { ...@@ -34,7 +34,7 @@ export default class Login extends React.Component {
componentDidMount() { componentDidMount() {
Client.isLoggedIn((data) => { Client.isLoggedIn((data) => {
if (data && data.logged_in) { if (data && data.logged_in) {
browserHistory.push('/companies'); browserHistory.push('/mailboxes');
} else { } else {
$('body').addClass('blank'); $('body').addClass('blank');
} }
...@@ -46,7 +46,7 @@ export default class Login extends React.Component { ...@@ -46,7 +46,7 @@ export default class Login extends React.Component {
this.setState({user}); this.setState({user});
if (user) { if (user) {
browserHistory.push('/companies'); browserHistory.push('/mailboxes');
} }
} }
submit(email, password) { submit(email, password) {
...@@ -71,7 +71,7 @@ export default class Login extends React.Component { ...@@ -71,7 +71,7 @@ export default class Login extends React.Component {
return Client.getAllCos( return Client.getAllCos(
(cosData) => { (cosData) => {
ZimbraStore.setAllCos(cosData); ZimbraStore.setAllCos(cosData);
browserHistory.push('/companies'); browserHistory.push('/mailboxes');
} }
); );
}, },
......
...@@ -2,17 +2,19 @@ ...@@ -2,17 +2,19 @@
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import React from 'react'; import React from 'react';
import {browserHistory} from 'react-router';
import {Modal} from 'react-bootstrap'; import {Modal} from 'react-bootstrap';
import UserStore from '../../stores/user_store.jsx'; import UserStore from '../../stores/user_store.jsx';
import PasswordStrengthMeter from 'react-password-strength-meter'; import PasswordStrengthMeter from 'react-password-strength-meter';
import * as GlobalActions from '../../action_creators/global_actions.jsx';
import Constants from '../../utils/constants.jsx';
const MessageTypes = Constants.MessageType;
export default class ConfirmDeleteModal extends React.Component { export default class ConfirmDeleteModal extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.handleChangePasswd = this.handleChangePasswd.bind(this); this.handleChangePasswd = this.handleChangePasswd.bind(this);
this.forceLogout = this.forceLogout.bind(this);
this.handlePasswd = this.handlePasswd.bind(this); this.handlePasswd = this.handlePasswd.bind(this);
this.restart = this.restart.bind(this); this.restart = this.restart.bind(this);
...@@ -36,12 +38,6 @@ export default class ConfirmDeleteModal extends React.Component { ...@@ -36,12 +38,6 @@ export default class ConfirmDeleteModal extends React.Component {
return {currentUser}; return {currentUser};
} }
forceLogout(path) {
setTimeout(() => {
browserHistory.push(path);
}, 3000);
}
handleChangePasswd() { handleChangePasswd() {
if (this.refs.passwdfield.value && this.refs.passwdfield.value.length > 0) { if (this.refs.passwdfield.value && this.refs.passwdfield.value.length > 0) {
if (this.refs.passwdfield.value.length < 9) { if (this.refs.passwdfield.value.length < 9) {
...@@ -53,15 +49,22 @@ export default class ConfirmDeleteModal extends React.Component { ...@@ -53,15 +49,22 @@ export default class ConfirmDeleteModal extends React.Component {
} }
this.props.data.setPassword(this.refs.passwdfield.value, () => { this.props.data.setPassword(this.refs.passwdfield.value, () => {
this.setState({ const message = {
alert: true, error: 'Su contraseña se ha sido cambiada éxitosamente.',
message: 'Su contraseña se ha sido cambiada éxitosamente.', typeError: MessageTypes.SUCCESS
typeError: 'text-success' };
});
if (this.props.show) {
this.props.onHide();
}
if (this.props.data.name === this.state.currentUser.name) { if (this.props.data.name === this.state.currentUser.name) {
this.forceLogout('/logout'); const alterMessage = `${message.error} Deberá iniciar sesión de nuevo.`;
message.error = alterMessage;
message.logout = true;
} }
GlobalActions.emitMessage(message);
}, (error) => { }, (error) => {
this.setState({ this.setState({
alert: true, alert: true,
......
...@@ -14,46 +14,103 @@ export default class FormVacacionesMailbox extends React.Component { ...@@ -14,46 +14,103 @@ export default class FormVacacionesMailbox extends React.Component {
super(props); super(props);
this.handleSaveAutoResp = this.handleSaveAutoResp.bind(this); this.handleSaveAutoResp = this.handleSaveAutoResp.bind(this);
this.dateStart = null;
this.dateEnd = null;
this.initialDate = Utils.setInitialDate();
}
handleChangeDate(x, from) {
const ref = this.refs[from];
const timestamp = Utils.getInitialDateFromTimestamp(x);
ref.value = timestamp;
} }
handleSaveAutoResp() { handleSaveAutoResp() {
const data = this.props.data; const data = this.props.data;
const refs = this.refs; const refs = this.refs;
let enabled = refs.zimbraPrefOutOfOfficeReplyEnabled.checked.toString().toUpperCase(); const attrs = {};
let formated = document.getElementById('zimbraPrefOutOfOfficeUntilDate').value.split('/').reverse().join('') + '000000Z'; const isEnabled = refs.zimbraPrefOutOfOfficeReplyEnabled.checked;
const start = refs.zimbraPrefOutOfOfficeFromDate.value;
const end = refs.zimbraPrefOutOfOfficeUntilDate.value;
let formatedStart = document.getElementById('zimbraPrefOutOfOfficeFromDate').value.split('/').reverse().join('') + '000000Z';
let formatedEnd = document.getElementById('zimbraPrefOutOfOfficeUntilDate').value.split('/').reverse().join('') + '000000Z';
if ((start > end) && isEnabled) {
GlobalActions.emitMessage({
error: 'La fecha en la que termina su respuesta automática, debe ser mayor que en la que comienza.',
typeError: messageType.ERROR
});
let attrs = { return false;
zimbraPrefOutOfOfficeReplyEnabled: enabled, } else if ((start === end) && isEnabled) {
zimbraPrefOutOfOfficeUntilDate: formated, GlobalActions.emitMessage({
zimbraPrefOutOfOfficeReply: refs.zimbraPrefOutOfOfficeReply.value error: 'La fecha en la que comienza su respuesta automática no puede ser la misma fecha en la que termina.',
}; typeError: messageType.ERROR
});
return false;
}
if (isEnabled) {
attrs.zimbraPrefOutOfOfficeReplyEnabled = isEnabled.toString().toUpperCase();
attrs.zimbraPrefOutOfOfficeReply = refs.zimbraPrefOutOfOfficeReply.value;
attrs.zimbraPrefOutOfOfficeUntilDate = formatedEnd;
attrs.zimbraPrefOutOfOfficeFromDate = formatedStart;
} else {
attrs.zimbraPrefOutOfOfficeReplyEnabled = isEnabled.toString().toUpperCase();
}
Client.modifyAccount(data.id, attrs, () => { Client.modifyAccount(data.id, attrs, () => {
GlobalActions.emitMessage({ GlobalActions.emitMessage({
error: 'Se ha modificado su respuesta de vacaciones con éxito.', error: 'Se ha modificado su respuesta de vacaciones con éxito.',
type: messageType.SUCCESS typeError: messageType.SUCCESS
}); });
}, (error) => { }, (error) => {
GlobalActions.emitMessage({ GlobalActions.emitMessage({
error: error.message, error: error.message,
type: messageType.ERROR typeError: messageType.ERROR
}); });
}); });
return null;
} }
componentDidMount() { componentDidMount() {
const data = this.props.data.attrs; const data = this.props.data.attrs;
if (data.hasOwnProperty('zimbraPrefOutOfOfficeReplyEnabled')) { if (data.hasOwnProperty('zimbraPrefOutOfOfficeReplyEnabled')) {
this.refs.zimbraPrefOutOfOfficeReplyEnabled.checked = data.zimbraPrefOutOfOfficeReplyEnabled.toString().toLowerCase() === 'true'; this.refs.zimbraPrefOutOfOfficeReplyEnabled.checked = data.zimbraPrefOutOfOfficeReplyEnabled.toString().toLowerCase() === 'true';
} }
if (data.hasOwnProperty('zimbraPrefOutOfOfficeUntilDate')) {
document.getElementById('zimbraPrefOutOfOfficeUntilDate').value = Utils.dateFormatted(data.zimbraPrefOutOfOfficeUntilDate, true, '/');
}
if (data.hasOwnProperty('zimbraPrefOutOfOfficeReply')) { if (data.hasOwnProperty('zimbraPrefOutOfOfficeReply')) {
this.refs.zimbraPrefOutOfOfficeReply.value = data.zimbraPrefOutOfOfficeReply; this.refs.zimbraPrefOutOfOfficeReply.value = data.zimbraPrefOutOfOfficeReply;
} }
if (this.dateStart) {
this.refs.zimbraPrefOutOfOfficeFromDate.value = Utils.forceTimestampFromHumanDate(this.dateStart);
}
if (this.dateEnd) {
this.refs.zimbraPrefOutOfOfficeUntilDate.value = Utils.forceTimestampFromHumanDate(this.dateEnd);
}
}
componentWillMount() {
const data = this.props.data.attrs;
if (data.hasOwnProperty('zimbraPrefOutOfOfficeFromDate')) {
this.dateStart = Utils.dateFormatted(data.zimbraPrefOutOfOfficeFromDate, true, '/');
} else {
this.dateStart = this.initialDate.formatted;
}
if (data.hasOwnProperty('zimbraPrefOutOfOfficeUntilDate')) {
this.dateEnd = Utils.dateFormatted(data.zimbraPrefOutOfOfficeUntilDate, true, '/');
} else {
this.dateEnd = this.initialDate.formatted;
}
} }
render() { render() {
...@@ -84,6 +141,33 @@ export default class FormVacacionesMailbox extends React.Component { ...@@ -84,6 +141,33 @@ export default class FormVacacionesMailbox extends React.Component {
</div> </div>
</div> </div>
<div className='form-group string'>
<label className='string required col-sm-3 control-label'>
{'Empieza el'}
</label>
<div className='col-sm-8'>
<DateTimeField
inputFormat='DD/MM/YYYY'
inputProps={
{
id: 'zimbraPrefOutOfOfficeFromDate',
readOnly: 'readOnly'
}
}
onChange={(x) => {
this.handleChangeDate(x, 'zimbraPrefOutOfOfficeFromDate');
}}
defaultText={this.dateStart}
mode={'date'}
/>
<input
type='hidden'
ref='zimbraPrefOutOfOfficeFromDate'
/>
</div>
</div>
<div className='form-group string'> <div className='form-group string'>
<label className='string required col-sm-3 control-label'> <label className='string required col-sm-3 control-label'>
{'Termina el'} {'Termina el'}
...@@ -98,6 +182,16 @@ export default class FormVacacionesMailbox extends React.Component { ...@@ -98,6 +182,16 @@ export default class FormVacacionesMailbox extends React.Component {
readOnly: 'readOnly' readOnly: 'readOnly'
} }
} }
onChange={(x) => {
this.handleChangeDate(x, 'zimbraPrefOutOfOfficeUntilDate');
}}
defaultText={this.dateEnd}
mode={'date'}
/>
<input
type='hidden'
ref='zimbraPrefOutOfOfficeUntilDate'
/> />
</div> </div>
</div> </div>
......
...@@ -46,6 +46,8 @@ export default class BlockGeneralInfoMailbox extends React.Component { ...@@ -46,6 +46,8 @@ export default class BlockGeneralInfoMailbox extends React.Component {
render() { render() {
let blockInfo = null; let blockInfo = null;
let statusCos = null; let statusCos = null;
console.log(ZimbraStore.getAllCos());
console.log(this.data);
const cosID = Utils.getEnabledPlansObjectByCos(ZimbraStore.getAllCos(), this.props.data.attrs.zimbraCOSId); const cosID = Utils.getEnabledPlansObjectByCos(ZimbraStore.getAllCos(), this.props.data.attrs.zimbraCOSId);
let cosName = null; let cosName = null;
......
...@@ -41,7 +41,9 @@ export default class Mailboxes extends React.Component { ...@@ -41,7 +41,9 @@ export default class Mailboxes extends React.Component {
const page = parseInt(this.props.location.query.page, 10) || 1; const page = parseInt(this.props.location.query.page, 10) || 1;
this.mailboxes = null; this.mailboxes = null;
this.status = ''; this.status = '';
this.cos = null; this.cos = Utils.getEnabledPlansByCos(ZimbraStore.getAllCos());
this.cosById = Utils.getEnabledPlansByCosId(ZimbraStore.getAllCos());
this.isRefreshing = true;
this.state = { this.state = {
page, page,
...@@ -146,7 +148,7 @@ export default class Mailboxes extends React.Component { ...@@ -146,7 +148,7 @@ export default class Mailboxes extends React.Component {
domainId = this.props.params.domain_id; domainId = this.props.params.domain_id;
this.getAllMailboxes(domainId); this.getAllMailboxes(domainId, window.manager_config.maxResultOnRequestZimbra);
} else { } else {
GlobalActions.emitStartLoading(); GlobalActions.emitStartLoading();
...@@ -154,7 +156,7 @@ export default class Mailboxes extends React.Component { ...@@ -154,7 +156,7 @@ export default class Mailboxes extends React.Component {
domainId = newProps.params.domain_id; domainId = newProps.params.domain_id;
} }
this.getAllMailboxes(domainId); this.getAllMailboxes(domainId, window.manager_config.maxResultOnRequestZimbra);
} }
} }
...@@ -180,8 +182,13 @@ export default class Mailboxes extends React.Component { ...@@ -180,8 +182,13 @@ export default class Mailboxes extends React.Component {
); );
} }
getAccounts(domainName) { getAccounts(domainName, maxResult) {
const attrs = {}; const attrs = {
limit: QueryOptions.DEFAULT_LIMIT,
maxResults: maxResult,
offset: this.state.offset
};
if (domainName) { if (domainName) {
attrs.domain = domainName; attrs.domain = domainName;
} }
...@@ -195,19 +202,23 @@ export default class Mailboxes extends React.Component { ...@@ -195,19 +202,23 @@ export default class Mailboxes extends React.Component {
}); });
} }
if (MailboxStore.hasMailboxes()) { if (MailboxStore.hasMailboxes() && MailboxStore.hasThisPage(this.state.page)) {
resolve(MailboxStore.getMailboxes()); console.log('has page with data');
return resolve(MailboxStore.getMailboxByPage(this.state.page));
} }
return Client.getAllAccounts(attrs, (success) => { return Client.getAllAccounts(attrs, (success) => {
MailboxStore.setMailboxes(success); MailboxStore.setMailboxes(success, this.state.page);
this.mailboxes = this.mailboxes = MailboxStore.getMailboxes(); this.mailboxes = MailboxStore.getMailboxes();
return resolve(success); return resolve(success);
}, (error) => { }, (error) => {
return reject(error); return reject(error);
}); });
}).then((data) => { }).then((data) => {
if (data.account) { if (data.account) {
this.isRefreshing = false;
const tables = this.buildTableFromData(data, ['Todas', 'Bloqueadas']); const tables = this.buildTableFromData(data, ['Todas', 'Bloqueadas']);
if (tables.lockedAlert) { if (tables.lockedAlert) {
...@@ -227,9 +238,18 @@ export default class Mailboxes extends React.Component { ...@@ -227,9 +238,18 @@ export default class Mailboxes extends React.Component {
domain: domainName domain: domainName
}); });
}).catch((error) => { }).catch((error) => {
return error; if (error.code === 'account.TOO_MANY_SEARCH_RESULTS') {
this.isRefreshing = true;
const newMaxResult = (parseInt(maxResult, 10) + window.manager_config.autoincrementOnFailRequestZimbra);
window.manager_config.maxResultOnRequestZimbra = newMaxResult;
setTimeout(() => {
this.getAccounts(domainName, newMaxResult);
}, 250);
}
}).finally(() => { }).finally(() => {
GlobalActions.emitEndLoading(); if (!this.isRefreshing) {
GlobalActions.emitEndLoading();
}
}); });
} }
...@@ -237,11 +257,11 @@ export default class Mailboxes extends React.Component { ...@@ -237,11 +257,11 @@ export default class Mailboxes extends React.Component {
if (domainId) { if (domainId) {
return this.domainInfo(domainId).then(() => { return this.domainInfo(domainId).then(() => {
const domain = DomainStore.getCurrent(); const domain = DomainStore.getCurrent();
this.getAccounts(domain.name); this.getAccounts(domain.name, window.manager_config.maxResultOnRequestZimbra);
}); });
} }
return this.getAccounts(); return this.getAccounts(null, window.manager_config.maxResultOnRequestZimbra);
} }
refreshAllAccounts() { refreshAllAccounts() {
...@@ -276,6 +296,29 @@ export default class Mailboxes extends React.Component { ...@@ -276,6 +296,29 @@ export default class Mailboxes extends React.Component {
buildRow(row, classes, status) { buildRow(row, classes, status) {
const id = row.id; const id = row.id;
const attrs = row.attrs;
let displayName = 'No definido';
let tipo = attrs.zimbraCOSId || null;
if (tipo) {
tipo = this.cosById[tipo] || null;
if (tipo) {
tipo = Utils.titleCase(tipo);
}
}
if (!tipo) {
tipo = 'Desconocido';
}
if (attrs.displayName) {
displayName = attrs.displayName.trim();
} else if (attrs.cn || attrs.sn) {
const cn = attrs.cn || '';
const sn = attrs.sn || '';
displayName = `${cn.trim()} ${sn.trim()}`;
}
return ( return (
<tr <tr
key={id} key={id}
...@@ -297,14 +340,14 @@ export default class Mailboxes extends React.Component { ...@@ -297,14 +340,14 @@ export default class Mailboxes extends React.Component {
</td> </td>
<td className={'mailbox-displayname'}> <td className={'mailbox-displayname'}>
{row.name} {displayName}
</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'}>{tipo}</statusLabel>
</td> </td>
<td> <td className='text-center'>
<Button <Button
btnAttrs={ btnAttrs={
{ {
...@@ -360,8 +403,8 @@ export default class Mailboxes extends React.Component { ...@@ -360,8 +403,8 @@ export default class Mailboxes extends React.Component {
<tr> <tr>
<th>{'Email'}</th> <th>{'Email'}</th>
<th className='td-mbxs text-left'>{'Nombre'}</th> <th className='td-mbxs text-left'>{'Nombre'}</th>
<th className='text-center text-center'>{'Tipo'}</th> <th className='text-left'>{'Tipo'}</th>
<th className='text-center text-center'>{'Acciones'}</th> <th className='text-center'>{'Acciones'}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
...@@ -416,7 +459,7 @@ export default class Mailboxes extends React.Component { ...@@ -416,7 +459,7 @@ export default class Mailboxes extends React.Component {
} }
const response = {}; const response = {};
const all = `${arrayTabNames.shift()} (${activeAccounts.length})`; const all = `${arrayTabNames.shift()} (${totalAccounts})`;
const locked = `${arrayTabNames.shift()} (${lockedAccounts.length})`; const locked = `${arrayTabNames.shift()} (${lockedAccounts.length})`;
// create structure html for all accountsç // create structure html for all accountsç
...@@ -461,7 +504,9 @@ export default class Mailboxes extends React.Component { ...@@ -461,7 +504,9 @@ export default class Mailboxes extends React.Component {
} }
]; ];
let activePagination = null; let activePagination = {
total: totalAccounts
};
const totalPage = Math.ceil(totalAccounts / QueryOptions.DEFAULT_LIMIT); const totalPage = Math.ceil(totalAccounts / QueryOptions.DEFAULT_LIMIT);
if (activeAccounts.length > QueryOptions.DEFAULT_LIMIT) { if (activeAccounts.length > QueryOptions.DEFAULT_LIMIT) {
activeAccounts = activeAccounts.slice(this.state.offset, (this.state.page * QueryOptions.DEFAULT_LIMIT)); activeAccounts = activeAccounts.slice(this.state.offset, (this.state.page * QueryOptions.DEFAULT_LIMIT));
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
import $ from 'jquery'; import $ from 'jquery';
import React from 'react'; import React from 'react';
import {browserHistory} from 'react-router';
import EventStore from '../../stores/event_store.jsx'; import EventStore from '../../stores/event_store.jsx';
...@@ -52,6 +53,12 @@ export default class MailboxDetails extends React.Component { ...@@ -52,6 +53,12 @@ export default class MailboxDetails extends React.Component {
error: attrs.error, error: attrs.error,
type: attrs.typeError type: attrs.typeError
}); });
if (attrs.logout) {
setTimeout(() => {
browserHistory.push('/logout');
}, 3000);
}
} }
onRemoveAlias(alias) { onRemoveAlias(alias) {
......
...@@ -19,7 +19,7 @@ export default class PageInfo extends React.Component { ...@@ -19,7 +19,7 @@ export default class PageInfo extends React.Component {
PageInfo.propTypes = { PageInfo.propTypes = {
titlePage: React.PropTypes.any.isRequired, titlePage: React.PropTypes.any.isRequired,
descriptionPage: React.PropTypes.string descriptionPage: React.PropTypes.any
}; };
PageInfo.defaultProps = { PageInfo.defaultProps = {
......
...@@ -60,7 +60,8 @@ export default class Pagination extends React.Component { ...@@ -60,7 +60,8 @@ export default class Pagination extends React.Component {
let prev; let prev;
let next; let next;
let last; let last;
let i = 1; let console;
//let i = 1;
if (current > 1 && current <= total) { if (current > 1 && current <= total) {
first = ( first = (
...@@ -96,9 +97,43 @@ export default class Pagination extends React.Component { ...@@ -96,9 +97,43 @@ export default class Pagination extends React.Component {
>{'Última'}</a> >{'Última'}</a>
</li> </li>
); );
console = (
<li key='console-page'>
<span>{`${current} de ${this.props.totalPages}`}</span>
</li>
);
} }
for (; i <= total; i++) { const rangeBack = current - this.props.range;
const rangeForward = ((current + this.props.range) + 1);
for (let p = rangeBack; p < rangeForward; p++) {
if ((p > 0) && (p <= total)) {
if (p === current) {
pages.push(
<li
key={`page-${p}`}
className='active'
>
<a remote='false'>{p.toString()}</a>
</li>
);
} else {
pages.push(
<li key={`page-${p}`}>
<a
onClick={this.handleChange}
>
{p.toString()}
</a>
</li>
);
}
}
}
/*for (; i <= total; i++) {
if (current === i) { if (current === i) {
pages.push( pages.push(
<li <li
...@@ -119,7 +154,7 @@ export default class Pagination extends React.Component { ...@@ -119,7 +154,7 @@ export default class Pagination extends React.Component {
</li> </li>
); );
} }
} }*/
return ( return (
<div id='pagination'> <div id='pagination'>
...@@ -129,6 +164,7 @@ export default class Pagination extends React.Component { ...@@ -129,6 +164,7 @@ export default class Pagination extends React.Component {
{pages} {pages}
{next} {next}
{last} {last}
{console}
</ul> </ul>
</div> </div>
); );
...@@ -138,5 +174,10 @@ export default class Pagination extends React.Component { ...@@ -138,5 +174,10 @@ export default class Pagination extends React.Component {
Pagination.propTypes = { Pagination.propTypes = {
url: React.PropTypes.string.isRequired, url: React.PropTypes.string.isRequired,
currentPage: React.PropTypes.number.isRequired, currentPage: React.PropTypes.number.isRequired,
totalPages: React.PropTypes.number.isRequired totalPages: React.PropTypes.number.isRequired,
range: React.PropTypes.number
}; };
Pagination.defaultProps = {
range: 2
}
...@@ -58,10 +58,26 @@ export default class ProgressTask extends React.Component { ...@@ -58,10 +58,26 @@ export default class ProgressTask extends React.Component {
}); });
} }
isTaskDuplicated(params) {
const id = params.id;
for (let i = 0; i < this.tasks.length; i++) {
const currentTask = this.tasks[i];
if (id === currentTask.id) {
return true;
}
}
return false;
}
showTasks(params) { showTasks(params) {
if (this.isTaskDuplicated(params)) {
return null;
}
this.tasks.push(params); this.tasks.push(params);
this.setState({ return this.setState({
show: true, show: true,
tasks: this.tasks, tasks: this.tasks,
total: this.tasks.length total: this.tasks.length
......
import React from 'react';
import PageInfo from '../page_info.jsx';
import * as GlobalActions from '../../action_creators/global_actions.jsx';
import * as Client from '../../utils/client.jsx';
import Button from '../button.jsx';
import * as Utils from '../../utils/utils.jsx';
import Panel from '../panel.jsx';
export default class SearchView extends React.Component {
constructor(props) {
super(props);
this.makeSearch = this.makeSearch.bind(this);
this.state = {};
}
componentDidMount() {
GlobalActions.emitEndLoading();
const query = this.props.params.query;
this.makeSearch(query);
}
componentWillReceiveProps(newProps) {
//const condition = (newProps.params.query !== this.props.params.query);
GlobalActions.emitEndLoading();
const query = newProps.params.query;
this.makeSearch(query);
};
makeSearch(query) {
Client.search({
query: `(|(mail=*${query}*)(cn=*${query}*)(sn=*${query}*)(gn=*${query}*)(displayName=*${query}*)(zimbraMailDeliveryAddress=*${query}*)(zimbraDomainName=*${query}*)(uid=*${query}*)(zimbraMailAlias=*${query}*)(uid=*${query}*)(zimbraDomainName=*${query}*)(cn=*${query}*))`,
types: 'accounts,distributionlists,domains'
}, (success) => {
const result = [];
for (const key in success) {
if (success.hasOwnProperty(key)) {
if (key === 'dl' || key === 'domain' || key === 'account') {
Array.prototype.push.apply(result, success[key]);
}
}
}
if (success.total <= 0) {
return this.setState({
notfound: true
});
}
return this.setState({
result
});
}, (error) => {
console.log(error);
});
}
render() {
const query = this.props.params.query;
let content = null;
const pagelInfo = (
<PageInfo
titlePage='Búsqueda'
descriptionPage={`Resultados para su búsqueda: ${query}`}
/>
);
if (this.state.result) {
const data = this.state.result;
const objectDomain = {};
const rows = data.map((item) => {
const type = item.constructor.name.toString().toLowerCase();
let tipo = 'Desconocido';
let url = null;
const id = item.id;
switch(type) {
case 'domain':
tipo = (
<div>
<i className='fa fa-globe fa-lg'></i>
<span className='marginLeft'>{'Dominio'}</span>
</div>
);
url = `/domains/${id}`;
objectDomain[item.name] = id;
break;
case 'account':
tipo = (
<div>
<i className='fa fa-user fa-lg'></i>
<span className='marginLeft'>{'Casilla'}</span>
</div>
);
url = `/mailboxes/${id}`;
break;
case 'distributionlist':
tipo = (
<div>
<i className='fa fa-users fa-lg'></i>
<span className='marginLeft'>{'Lista de Distribución'}</span>
</div>
);
const dlName = item.name.indexOf('@') > -1 ? item.name.split('@').pop() : item.name;
let domainId = null;
if (objectDomain[dlName]) {
domainId = objectDomain[dlName];
} else {
domainId = Utils.getDomainIdFromDL(item.name, data);
}
url = `/domains/${domainId}/distribution_lists/${id}`;
break;
}
return (
<tr
key={id}
className={'mailbox-row'}
>
<td className={'mailbox-name'}>
{tipo}
</td>
<td className={'mailbox-displayname'}>
{item.name}
</td>
<td className={'text-right'}>
<Button
btnAttrs={
{
className: 'btn btn-xs btn-info',
onClick: (e) => Utils.handleLink(e, url)
}
}
>
{'Ver'}
</Button>
</td>
</tr>
);
});
const table = (
<div
key='mailbox'
id='index-mailboxes-table'
className='table-responsive'
>
<table
id='index-domains'
cellPadding='1'
cellSpacing='1'
className='table table-condensed table-striped vertical-align index-mailbox-table'
>
<thead>
<tr>
<th className='text-left'>{'Tipo'}</th>
<th className='td-mbxs text-left'>{'Nombre'}</th>
<th className='text-right'>{'Acciones'}</th>
</tr>
</thead>
<tbody>
{rows}
</tbody>
</table>
</div>
);
content = (
<Panel
children={table}
hasHeader={false}
/>
);
}
if (this.state.notfound) {
content = (
<div className='text-center'>
<h4>
No existen resultados para su búsqueda
</h4>
</div>
);
}
return (
<div>
{pagelInfo}
<div className='content animate-panel'>
<div className='row'>
<div className='col-md-12 panel-with-tabs'>
{content}
</div>
</div>
</div>
</div>
);
}
}
SearchView.propTypes = {
params: React.PropTypes.object
};
...@@ -24,14 +24,6 @@ export default class SidebarMenu extends React.Component { ...@@ -24,14 +24,6 @@ export default class SidebarMenu extends React.Component {
className='nav' className='nav'
id='side-menu' id='side-menu'
> >
<li id='sidebar-dashboards'>
<a
href='#'
onClick={(e) => this.handleLink(e, '/dashboards')}
>
<span className='nav-label'>{'dashboards'}</span>
</a>
</li>
<li id='sidebar-companies'> <li id='sidebar-companies'>
<a <a
href='#' href='#'
......
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
"url": "http://192.168.1.8:8081", "url": "http://192.168.1.8:8081",
"token": "otto" "token": "otto"
}, },
"maxResultOnRequestZimbra": 4000,
"autoincrementOnFailRequestZimbra": 500,
"plans": { "plans": {
"basic": true, "basic": true,
"premium": true, "premium": true,
......
...@@ -22,6 +22,7 @@ import CreateMailBox from './components/mailbox/create_mailbox.jsx'; ...@@ -22,6 +22,7 @@ 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 DistributionLists from './components/distribution/distribution_lists.jsx';
import EditDistributionList from './components/distribution/edit_distribution_lists.jsx'; import EditDistributionList from './components/distribution/edit_distribution_lists.jsx';
import SearchView from './components/search/search.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';
...@@ -156,18 +157,18 @@ function renderRootComponent() { ...@@ -156,18 +157,18 @@ function renderRootComponent() {
component={EditDistributionList} component={EditDistributionList}
/> />
<Route <Route
path='companies' path='companies'
component={Companies} component={Companies}
/> />
<Route <Route
path='companies/:id' path='companies/:id'
component={Company} component={Company}
/> />
<Route <Route
path='companies/:id/domains/new' path='companies/:id/domains/new'
component={CreateDomains} component={CreateDomains}
/> />
<Route <Route
path='mailboxes' path='mailboxes'
...@@ -193,6 +194,11 @@ function renderRootComponent() { ...@@ -193,6 +194,11 @@ function renderRootComponent() {
path='logout' path='logout'
onEnter={onLoggedOut} onEnter={onLoggedOut}
/> />
<Route
path='search/:query'
component={SearchView}
/>
</Route> </Route>
<Route component={NotLoggedIn}> <Route component={NotLoggedIn}>
<IndexRedirect to='login'/> <IndexRedirect to='login'/>
......
...@@ -3,3 +3,4 @@ ...@@ -3,3 +3,4 @@
@import 'domain'; @import 'domain';
@import 'companies'; @import 'companies';
@import 'mailbox'; @import 'mailbox';
@import 'search';
.marginLeft {
margin-left: 5px;
}
...@@ -7,11 +7,13 @@ import Constants from '../utils/constants.jsx'; ...@@ -7,11 +7,13 @@ import Constants from '../utils/constants.jsx';
const eventTypes = Constants.EventTypes; const eventTypes = Constants.EventTypes;
let mailboxesArray = null; let mailboxesArray = null;
let mailboxexInstances = [];
class MailboxStoreClass extends EventEmitter { class MailboxStoreClass extends EventEmitter {
constructor() { constructor() {
super(); super();
this.current = null; this.current = null;
this.currentPage = {};
} }
getMailboxById(id) { getMailboxById(id) {
...@@ -38,6 +40,27 @@ class MailboxStoreClass extends EventEmitter { ...@@ -38,6 +40,27 @@ class MailboxStoreClass extends EventEmitter {
} }
} }
hasThisPage(page) {
if (page && this.currentPage[page]) {
return this.currentPage[page];
}
return false;
}
setCurrentPage(page) {
this.currentPage[page] = true;
}
getMailboxByPage(page) {
if (page && this.currentPage[page]) {
console.log(this.currentPage);
return this.currentPage[page];
}
return false;
}
setCurrent(account) { setCurrent(account) {
this.current = account; this.current = account;
} }
...@@ -54,12 +77,33 @@ class MailboxStoreClass extends EventEmitter { ...@@ -54,12 +77,33 @@ class MailboxStoreClass extends EventEmitter {
return false; return false;
} }
getPages() {
return this.currentPage;
}
getMailboxes() { getMailboxes() {
return mailboxesArray; return mailboxesArray;
} }
setMailboxes(mailboxes) { setMailboxes(mailboxes, page) {
if (mailboxesArray) {
Array.prototype.push.apply(mailboxexInstances, mailboxes.account);
mailboxesArray.account = mailboxexInstances;
console.log('mailbox', mailboxes);
if (page) {
this.currentPage[page] = mailboxes;
console.log(this.currentPage[page]);
}
return true;
}
mailboxesArray = mailboxes; mailboxesArray = mailboxes;
mailboxexInstances = mailboxes.account;
if (page) {
this.currentPage[page] = mailboxes;
console.log(this.currentPage[page]);
}
return true;
} }
changeAccount(newAccount) { changeAccount(newAccount) {
......
...@@ -29,6 +29,7 @@ function handleError(methodName, err) { ...@@ -29,6 +29,7 @@ function handleError(methodName, err) {
if (err) { if (err) {
error.message = err.extra.reason; error.message = err.extra.reason;
error.code = err.extra.code || null;
} else { } else {
error.message = 'Ocurrio un error general'; error.message = 'Ocurrio un error general';
} }
...@@ -111,7 +112,7 @@ export function login(user, password, success, error) { ...@@ -111,7 +112,7 @@ export function login(user, password, success, error) {
} }
Utils.setCookie('token', zimbra.client.token); Utils.setCookie('token', zimbra.client.token);
ZimbraStore.setCurrent(zimbra); window.manager_config.dns.token = Utils.getCookie('token');
return getMe(success, error); return getMe(success, error);
}); });
} }
...@@ -524,9 +525,7 @@ export function search(query, success, error) { ...@@ -524,9 +525,7 @@ export function search(query, success, error) {
initZimbra().then( initZimbra().then(
(zimbra) => { (zimbra) => {
zimbra.directorySearch( zimbra.directorySearch(
{ query,
query
},
(err, data) => { (err, data) => {
if (err) { if (err) {
const e = handleError('search', err); const e = handleError('search', err);
......
...@@ -544,3 +544,59 @@ export function getOwners(owners) { ...@@ -544,3 +544,59 @@ export function getOwners(owners) {
throw Error('Owners array no es un arreglo :' + typeof owners); throw Error('Owners array no es un arreglo :' + typeof owners);
} }
export function getDomainIdFromDL(dlName, arr) {
const domainName = dlName.indexOf('@') > -1 ? dlName.split('@').pop() : dlName;
for (const domain in arr) {
if (arr.hasOwnProperty(domain)) {
if (domain.constructor.name.toString().toLowerCase() === 'domain') {
if (arr[domain].name === domainName) {
return arr[domain];
}
}
}
}
}
export function getInitialDateFromTimestamp(timestamp) {
const time = parseInt(timestamp, 10);
const date = new Date(time).toLocaleString();
let dateParts = date.split('/');
const lastPosition = dateParts.pop();
const formattedLastPosition = lastPosition.substring(0, 4);
dateParts.push(formattedLastPosition);
const timestampReseted = new Date(dateParts[2], (parseInt(dateParts[1], 10) - 1).toString(), dateParts[0], '00', '00', '00').getTime();
return timestampReseted;
}
export function forceTimestampFromHumanDate(date) {
const arrDate = date.split('/').reverse();
const newDateArr = arrDate.map((pos, i) => {
let item = parseInt(pos, 10);
if (i === 1) {
const tmp = item - 1;
item = tmp;
}
return item;
});
const formattedTimeStamp = new Date(newDateArr[0], newDateArr[1], newDateArr[2], '00', '00', '00').getTime();
return formattedTimeStamp;
}
export function setInitialDate(){
const dateInstance = new Date();
const day = dateInstance.getDate().toString().length < 2 ? '0' + dateInstance.getDate().toString() : dateInstance.getDate();
const month = (dateInstance.getMonth() + 1).toString().length < 2 ? '0' + (dateInstance.getMonth() + 1).toString() : (dateInstance.getMonth() + 1);
const formatted = `${day}/${month}/${dateInstance.getFullYear()}`;
const date = new Date(dateInstance.getFullYear(), dateInstance.getMonth(), dateInstance.getDate(), '00','00','00').getTime();
const dateObject = {
timestamp: date,
formatted
};
return dateObject;
}
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