Commit 58b41f50 authored by Elias Nahum's avatar Elias Nahum Committed by Juorder Antonio

many issues resolved, list, and modify task massive from domain, in parts,...

many issues resolved, list, and modify task massive from domain, in parts, solved modal change password, etc
parent c82ac91a
module.exports = {"main":{"js":"/244695bundle.js"}}
\ No newline at end of file
module.exports = {"main":{"js":"/887398bundle.js"}}
\ No newline at end of file
......@@ -20,8 +20,8 @@ export default class AntiSpam extends React.Component {
this.handleSave = this.handleSave.bind(this);
this.alterDomain = this.alterDomain.bind(this);
this.domain = DomainStore.getCurrent();
this.blackList = null;
this.whiteList = null;
this.blackList = [];
this.whiteList = [];
if (this.domain.attrs.amavisBlacklistSender) {
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 {
switch (action) {
case 'black':
this.searchItemToRemove(this.blackList, item);
attrs.amavisBlacklistSender = this.blackList;
attrs.amavisBlacklistSender = this.blackList.length > 0 ? this.blackList : null;
break;
case 'white':
this.searchItemToRemove(this.whiteList, item);
attrs.amavisWhitelistSender = this.whiteList;
attrs.amavisWhitelistSender = this.whiteList.length > 0 ? this.whiteList : null;
break;
}
......
......@@ -111,6 +111,7 @@ export default class DomainMailboxPlans extends React.Component {
);
}
} else {
console.log(totalLimit);
totalLimit += plan.limit;
}
......
......@@ -17,6 +17,7 @@ import * as Client from '../../utils/client.jsx';
import * as Utils from '../../utils/utils.jsx';
import * as GlobalActions from '../../action_creators/global_actions.jsx';
import Constants from '../../utils/constants.jsx';
import UserStore from '../../stores/user_store.jsx';
const QueryOptions = Constants.QueryOptions;
const messageType = Constants.MessageType;
......@@ -28,12 +29,14 @@ export default class Domains extends React.Component {
this.getDomains = this.getDomains.bind(this);
const page = parseInt(this.props.location.query.page, 10) || 1;
this.isGlobalAdmin = UserStore.isGlobalAdmin();
this.state = {
page,
offset: ((page - 1) * QueryOptions.DEFAULT_LIMIT)
};
}
getDomains() {
const self = this;
Client.getAllDomains(
......@@ -72,6 +75,7 @@ export default class Domains extends React.Component {
}
);
}
getPlans(domains) {
const names = domains.map((d) => {
return d.name;
......@@ -110,6 +114,7 @@ export default class Domains extends React.Component {
$('#sidebar-domains').addClass('active');
this.getDomains();
}
componentWillUnmount() {
$('#sidebar-domains').removeClass('active');
}
......@@ -117,6 +122,7 @@ export default class Domains extends React.Component {
render() {
const error = this.state.error;
let message;
let addDomainButton = null;
if (error) {
message = (
<MessageBar
......@@ -127,7 +133,8 @@ export default class Domains extends React.Component {
);
}
const addDomainButton = [{
if (this.isGlobalAdmin) {
addDomainButton = [{
label: 'Agregar Dominio',
props: {
className: 'btn btn-success',
......@@ -136,6 +143,7 @@ export default class Domains extends React.Component {
}
}
}];
}
let tableResults;
if (this.state.data) {
......@@ -233,7 +241,7 @@ export default class Domains extends React.Component {
<thead>
<tr>
<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'>{'Estado'}</th>
</tr>
......
......@@ -8,6 +8,7 @@ import DateTimeField from 'react-bootstrap-datetimepicker';
import * as Client from '../../utils/client.jsx';
import Promise from 'bluebird';
import * as GlobalActions from '../../action_creators/global_actions.jsx';
import * as Utils from '../../utils/utils.jsx';
export default class MultipleTaskModal extends React.Component {
constructor(props) {
......@@ -16,25 +17,58 @@ export default class MultipleTaskModal extends React.Component {
this.onSubmit = this.onSubmit.bind(this);
this.getOwnAccounts = this.getOwnAccounts.bind(this);
this.handleChangeDate = this.handleChangeDate.bind(this);
this.allAccounts = [];
this.loop = 0;
this.range = 200;
this.initialDate = Utils.setInitialDate();
this.dateStart = this.initialDate.formatted;
this.dateEnd = this.initialDate.formatted;
this.timestampStart = this.initialDate.timestamp;
this.timestampEnd = this.initialDate.timestamp;
this.state = {
loaded: false
};
}
handleChangeDate() {
const timeLapse = 100;
setTimeout(() => {
const formated = document.getElementById('zimbraPrefOutOfOfficeUntilDate').value.split('/').reverse().join('') + '000000Z';
this.refs.zimbraPrefOutOfOfficeUntilDate.value = formated;
}, timeLapse);
handleChangeDate(x, from) {
const ref = this.refs[from];
const timestamp = Utils.getInitialDateFromTimestamp(x);
ref.value = timestamp;
}
onSubmit() {
const accounts = this.state.accounts.account;
const accounts = this.allAccounts;
const domain = this.props.data;
const total = accounts.length;
const collection = [];
const refs = this.refs;
let message = null;
let error = false;
const isEnabled = refs.zimbraPrefOutOfOfficeReplyEnabled.checked;
const start = refs.zimbraPrefOutOfOfficeFromDate.value;
const end = refs.zimbraPrefOutOfOfficeUntilDate.value;
if ((start > end) && isEnabled) {
message = 'La fecha en la que termina su respuesta automática, debe ser mayor que en la que comienza.';
error = true;
} else if ((start === end) && isEnabled) {
message = 'La fecha en la que comienza su respuesta automática no puede ser la misma fecha en la que termina.';
error = true;
}
if (error) {
this.setState({
error: true,
message,
typeError: 'text-danger'
});
return false;
}
GlobalActions.emitStartTask({
origin: 'Dominio - Tareas Masivas',
......@@ -42,22 +76,31 @@ export default class MultipleTaskModal extends React.Component {
action: `Asignando mensaje masivo fuera de oficina a ${total}`
});
this.setState({
error: false
});
const attrs = {};
const isEnabled = this.refs.zimbraPrefOutOfOfficeReplyEnabled.checked;
if (isEnabled) {
attrs.zimbraPrefOutOfOfficeReplyEnabled = isEnabled.toString().toUpperCase();
attrs.zimbraPrefOutOfOfficeReply = this.refs.zimbraPrefOutOfOfficeReply.value;
attrs.zimbraPrefOutOfOfficeUntilDate = this.refs.zimbraPrefOutOfOfficeUntilDate.value;
attrs.zimbraPrefOutOfOfficeReply = refs.zimbraPrefOutOfOfficeReply.value;
attrs.zimbraPrefOutOfOfficeUntilDate = refs.zimbraPrefOutOfOfficeUntilDate.value;
attrs.zimbraPrefOutOfOfficeFromDate = refs.zimbraPrefOutOfOfficeFromDate.value;
} else {
attrs.zimbraPrefOutOfOfficeReplyEnabled = isEnabled.toString().toUpperCase();
}
accounts.forEach((account) => {
const initial = (this.loop * this.range);
const limitLoop = ((initial + this.range) > total) ? total : (initial + this.range);
for (let i = initial; i < limitLoop; i++) {
const account = accounts[i];
collection.push(Client.modifyAccountByBatch(account.id, attrs));
});
}
Client.batchRequest(collection, () => {
if (limitLoop === total) {
GlobalActions.emitEndTask({
id: 'dominio-massive-task',
toast: {
......@@ -69,30 +112,81 @@ export default class MultipleTaskModal extends React.Component {
if (this.props.show) {
this.props.onHide();
}
}, () => {
this.loop = 0;
this.allAccounts = [];
return true;
}
setTimeout(() => {
this.onSubmit();
}, 200);
return null;
}, (error) => {
console.log(error);
if (this.props.show) {
this.props.onHide();
}
});
}
getOwnAccounts() {
getOwnAccounts(attrs) {
const attributes = attrs || {};
const domain = this.props.data;
attributes.domain = domain.name;
attributes.maxResults = window.manager_config.maxResultOnRequestZimbra;
new Promise((resolve, reject) => {
Client.getAllAccounts({
domain: domain.name
}, (success) => {
Client.getAllAccounts(attributes, (success) => {
return resolve(success);
}, (err) => {
return reject(err);
});
}).then((res) => {
this.setState({
if (res.more) {
const result = res.account;
Array.prototype.push.apply(this.allAccounts, result);
if (res.total > this.allAccounts.length) {
this.loop++;
attributes.offset = (this.loop * attributes.limit);
setTimeout(() => {
this.getOwnAccounts(attributes);
}, 250);
}
}
if (!res.more) {
const finalResult = res.account;
Array.prototype.push.apply(this.allAccounts, finalResult);
this.loop = 0;
return this.setState({
loaded: true,
accounts: res
loading: false
});
}
const total = res.total;
const loaded = this.allAccounts.length;
return this.setState({
loading: true,
messageLoading: `Cargando ${loaded} de ${total} casillas...`
});
}).catch((error) => {
return error;
//return error;
if (error.code === 'account.TOO_MANY_SEARCH_RESULTS') {
const newMaxResultOnRequest = window.manager_config.maxResultOnRequestZimbra + window.manager_config.autoincrementOnFailRequestZimbra;
window.manager_config.maxResultOnRequestZimbra = newMaxResultOnRequest;
attributes.maxResults = newMaxResultOnRequest;
attributes.limit = window.manager_config.autoincrementOnFailRequestZimbra;
attributes.offset = this.loop;
setTimeout(() => {
this.getOwnAccounts(attributes);
}, 250);
}
});
}
......@@ -102,6 +196,19 @@ export default class MultipleTaskModal extends React.Component {
render() {
let content = null;
let messageLoading = 'Cargando...';
let labelError = null;
if (this.state.loading) {
const message = this.state.messageLoading;
messageLoading = message;
}
if (this.state.error) {
labelError = (
<label className={this.state.typeError}>{this.state.message}</label>
);
}
if (this.state.loaded) {
content = (
......@@ -128,6 +235,34 @@ export default class MultipleTaskModal extends React.Component {
</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'
value={this.timestampStart}
/>
</div>
</div>
<div className='form-group string'>
<label className='string required col-sm-3 control-label'>
{'Termina el'}
......@@ -142,12 +277,16 @@ export default class MultipleTaskModal extends React.Component {
readOnly: 'readOnly'
}
}
onChange={this.handleChangeDate}
defaultText={this.dateEnd}
onChange={(x) => {
this.handleChangeDate(x, 'zimbraPrefOutOfOfficeUntilDate');
}}
mode={'date'}
/>
<input
type='hidden'
ref='zimbraPrefOutOfOfficeUntilDate'
value={this.timestampEnd}
/>
</div>
</div>
......@@ -174,7 +313,7 @@ export default class MultipleTaskModal extends React.Component {
content = (
<div className='text-center'>
<i className='fa fa-spinner fa-spin fa-3x fa-fw'></i>
<p>Cargando...</p>
<p>{messageLoading}</p>
</div>
);
}
......@@ -195,6 +334,10 @@ export default class MultipleTaskModal extends React.Component {
<div>
{content}
</div>
<div className='text-center'>
<br/>
{labelError}
</div>
</Modal.Body>
<Modal.Footer>
<button
......
......@@ -7,6 +7,7 @@ import ReactDOM from 'react-dom';
import * as GlobalActions from '../action_creators/global_actions.jsx';
import {browserHistory, Link} from 'react-router';
import * as Utils from '../utils/utils.jsx';
import logo from '../images/logo.png';
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.toggleSidebar = this.toggleSidebar.bind(this);
}
handleSearch(e) {
e.preventDefault();
const search = ReactDOM.findDOMNode(this.refs.query);
......@@ -22,11 +24,14 @@ export default class Header extends React.Component {
const utf8 = ReactDOM.findDOMNode(this.refs.utf8).value.trim();
search.value = '';
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() {
$('body').toggleClass('hide-sidebar').toggleClass('show-sidebar');
}
render() {
return (
<div id='header'>
......
......@@ -34,7 +34,7 @@ export default class Login extends React.Component {
componentDidMount() {
Client.isLoggedIn((data) => {
if (data && data.logged_in) {
browserHistory.push('/companies');
browserHistory.push('/mailboxes');
} else {
$('body').addClass('blank');
}
......@@ -46,7 +46,7 @@ export default class Login extends React.Component {
this.setState({user});
if (user) {
browserHistory.push('/companies');
browserHistory.push('/mailboxes');
}
}
submit(email, password) {
......@@ -71,7 +71,7 @@ export default class Login extends React.Component {
return Client.getAllCos(
(cosData) => {
ZimbraStore.setAllCos(cosData);
browserHistory.push('/companies');
browserHistory.push('/mailboxes');
}
);
},
......
......@@ -2,17 +2,19 @@
// See LICENSE.txt for license information.
import React from 'react';
import {browserHistory} from 'react-router';
import {Modal} from 'react-bootstrap';
import UserStore from '../../stores/user_store.jsx';
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 {
constructor(props) {
super(props);
this.handleChangePasswd = this.handleChangePasswd.bind(this);
this.forceLogout = this.forceLogout.bind(this);
this.handlePasswd = this.handlePasswd.bind(this);
this.restart = this.restart.bind(this);
......@@ -36,12 +38,6 @@ export default class ConfirmDeleteModal extends React.Component {
return {currentUser};
}
forceLogout(path) {
setTimeout(() => {
browserHistory.push(path);
}, 3000);
}
handleChangePasswd() {
if (this.refs.passwdfield.value && this.refs.passwdfield.value.length > 0) {
if (this.refs.passwdfield.value.length < 9) {
......@@ -53,15 +49,22 @@ export default class ConfirmDeleteModal extends React.Component {
}
this.props.data.setPassword(this.refs.passwdfield.value, () => {
this.setState({
alert: true,
message: 'Su contraseña se ha sido cambiada éxitosamente.',
typeError: 'text-success'
});
const message = {
error: 'Su contraseña se ha sido cambiada éxitosamente.',
typeError: MessageTypes.SUCCESS
};
if (this.props.show) {
this.props.onHide();
}
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) => {
this.setState({
alert: true,
......
......@@ -14,46 +14,103 @@ export default class FormVacacionesMailbox extends React.Component {
super(props);
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() {
const data = this.props.data;
const refs = this.refs;
let enabled = refs.zimbraPrefOutOfOfficeReplyEnabled.checked.toString().toUpperCase();
let formated = document.getElementById('zimbraPrefOutOfOfficeUntilDate').value.split('/').reverse().join('') + '000000Z';
const attrs = {};
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 = {
zimbraPrefOutOfOfficeReplyEnabled: enabled,
zimbraPrefOutOfOfficeUntilDate: formated,
zimbraPrefOutOfOfficeReply: refs.zimbraPrefOutOfOfficeReply.value
};
return false;
} else if ((start === end) && isEnabled) {
GlobalActions.emitMessage({
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, () => {
GlobalActions.emitMessage({
error: 'Se ha modificado su respuesta de vacaciones con éxito.',
type: messageType.SUCCESS
typeError: messageType.SUCCESS
});
}, (error) => {
GlobalActions.emitMessage({
error: error.message,
type: messageType.ERROR
typeError: messageType.ERROR
});
});
return null;
}
componentDidMount() {
const data = this.props.data.attrs;
if (data.hasOwnProperty('zimbraPrefOutOfOfficeReplyEnabled')) {
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')) {
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() {
......@@ -84,6 +141,33 @@ export default class FormVacacionesMailbox extends React.Component {
</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'>
<label className='string required col-sm-3 control-label'>
{'Termina el'}
......@@ -98,6 +182,16 @@ export default class FormVacacionesMailbox extends React.Component {
readOnly: 'readOnly'
}
}
onChange={(x) => {
this.handleChangeDate(x, 'zimbraPrefOutOfOfficeUntilDate');
}}
defaultText={this.dateEnd}
mode={'date'}
/>
<input
type='hidden'
ref='zimbraPrefOutOfOfficeUntilDate'
/>
</div>
</div>
......
......@@ -46,6 +46,8 @@ export default class BlockGeneralInfoMailbox extends React.Component {
render() {
let blockInfo = null;
let statusCos = null;
console.log(ZimbraStore.getAllCos());
console.log(this.data);
const cosID = Utils.getEnabledPlansObjectByCos(ZimbraStore.getAllCos(), this.props.data.attrs.zimbraCOSId);
let cosName = null;
......
......@@ -41,7 +41,9 @@ export default class Mailboxes extends React.Component {
const page = parseInt(this.props.location.query.page, 10) || 1;
this.mailboxes = null;
this.status = '';
this.cos = null;
this.cos = Utils.getEnabledPlansByCos(ZimbraStore.getAllCos());
this.cosById = Utils.getEnabledPlansByCosId(ZimbraStore.getAllCos());
this.isRefreshing = true;
this.state = {
page,
......@@ -146,7 +148,7 @@ export default class Mailboxes extends React.Component {
domainId = this.props.params.domain_id;
this.getAllMailboxes(domainId);
this.getAllMailboxes(domainId, window.manager_config.maxResultOnRequestZimbra);
} else {
GlobalActions.emitStartLoading();
......@@ -154,7 +156,7 @@ export default class Mailboxes extends React.Component {
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 {
);
}
getAccounts(domainName) {
const attrs = {};
getAccounts(domainName, maxResult) {
const attrs = {
limit: QueryOptions.DEFAULT_LIMIT,
maxResults: maxResult,
offset: this.state.offset
};
if (domainName) {
attrs.domain = domainName;
}
......@@ -195,19 +202,23 @@ export default class Mailboxes extends React.Component {
});
}
if (MailboxStore.hasMailboxes()) {
resolve(MailboxStore.getMailboxes());
if (MailboxStore.hasMailboxes() && MailboxStore.hasThisPage(this.state.page)) {
console.log('has page with data');
return resolve(MailboxStore.getMailboxByPage(this.state.page));
}
return Client.getAllAccounts(attrs, (success) => {
MailboxStore.setMailboxes(success);
this.mailboxes = this.mailboxes = MailboxStore.getMailboxes();
MailboxStore.setMailboxes(success, this.state.page);
this.mailboxes = MailboxStore.getMailboxes();
return resolve(success);
}, (error) => {
return reject(error);
});
}).then((data) => {
if (data.account) {
this.isRefreshing = false;
const tables = this.buildTableFromData(data, ['Todas', 'Bloqueadas']);
if (tables.lockedAlert) {
......@@ -227,9 +238,18 @@ export default class Mailboxes extends React.Component {
domain: domainName
});
}).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(() => {
if (!this.isRefreshing) {
GlobalActions.emitEndLoading();
}
});
}
......@@ -237,11 +257,11 @@ export default class Mailboxes extends React.Component {
if (domainId) {
return this.domainInfo(domainId).then(() => {
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() {
......@@ -276,6 +296,29 @@ export default class Mailboxes extends React.Component {
buildRow(row, classes, status) {
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 (
<tr
key={id}
......@@ -297,14 +340,14 @@ export default class Mailboxes extends React.Component {
</td>
<td className={'mailbox-displayname'}>
{row.name}
{displayName}
</td>
<td className={'mailbox-cos-plan'}>
<statusLabel className={'label-plan label-unknown'}>{'unknown'}</statusLabel>
<statusLabel className={'label-plan label-unknown'}>{tipo}</statusLabel>
</td>
<td>
<td className='text-center'>
<Button
btnAttrs={
{
......@@ -360,8 +403,8 @@ export default class Mailboxes extends React.Component {
<tr>
<th>{'Email'}</th>
<th className='td-mbxs text-left'>{'Nombre'}</th>
<th className='text-center text-center'>{'Tipo'}</th>
<th className='text-center text-center'>{'Acciones'}</th>
<th className='text-left'>{'Tipo'}</th>
<th className='text-center'>{'Acciones'}</th>
</tr>
</thead>
<tbody>
......@@ -416,7 +459,7 @@ export default class Mailboxes extends React.Component {
}
const response = {};
const all = `${arrayTabNames.shift()} (${activeAccounts.length})`;
const all = `${arrayTabNames.shift()} (${totalAccounts})`;
const locked = `${arrayTabNames.shift()} (${lockedAccounts.length})`;
// create structure html for all accountsç
......@@ -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);
if (activeAccounts.length > QueryOptions.DEFAULT_LIMIT) {
activeAccounts = activeAccounts.slice(this.state.offset, (this.state.page * QueryOptions.DEFAULT_LIMIT));
......
......@@ -3,6 +3,7 @@
import $ from 'jquery';
import React from 'react';
import {browserHistory} from 'react-router';
import EventStore from '../../stores/event_store.jsx';
......@@ -52,6 +53,12 @@ export default class MailboxDetails extends React.Component {
error: attrs.error,
type: attrs.typeError
});
if (attrs.logout) {
setTimeout(() => {
browserHistory.push('/logout');
}, 3000);
}
}
onRemoveAlias(alias) {
......
......@@ -19,7 +19,7 @@ export default class PageInfo extends React.Component {
PageInfo.propTypes = {
titlePage: React.PropTypes.any.isRequired,
descriptionPage: React.PropTypes.string
descriptionPage: React.PropTypes.any
};
PageInfo.defaultProps = {
......
......@@ -60,7 +60,8 @@ export default class Pagination extends React.Component {
let prev;
let next;
let last;
let i = 1;
let console;
//let i = 1;
if (current > 1 && current <= total) {
first = (
......@@ -96,9 +97,43 @@ export default class Pagination extends React.Component {
>{'Última'}</a>
</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) {
pages.push(
<li
......@@ -119,7 +154,7 @@ export default class Pagination extends React.Component {
</li>
);
}
}
}*/
return (
<div id='pagination'>
......@@ -129,6 +164,7 @@ export default class Pagination extends React.Component {
{pages}
{next}
{last}
{console}
</ul>
</div>
);
......@@ -138,5 +174,10 @@ export default class Pagination extends React.Component {
Pagination.propTypes = {
url: React.PropTypes.string.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 {
});
}
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) {
if (this.isTaskDuplicated(params)) {
return null;
}
this.tasks.push(params);
this.setState({
return this.setState({
show: true,
tasks: this.tasks,
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 {
className='nav'
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'>
<a
href='#'
......
......@@ -8,6 +8,8 @@
"url": "http://192.168.1.8:8081",
"token": "otto"
},
"maxResultOnRequestZimbra": 4000,
"autoincrementOnFailRequestZimbra": 500,
"plans": {
"basic": true,
"premium": true,
......
......@@ -22,6 +22,7 @@ import CreateMailBox from './components/mailbox/create_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 SearchView from './components/search/search.jsx';
import * as Client from './utils/client.jsx';
import * as Utils from './utils/utils.jsx';
......@@ -193,6 +194,11 @@ function renderRootComponent() {
path='logout'
onEnter={onLoggedOut}
/>
<Route
path='search/:query'
component={SearchView}
/>
</Route>
<Route component={NotLoggedIn}>
<IndexRedirect to='login'/>
......
......@@ -3,3 +3,4 @@
@import 'domain';
@import 'companies';
@import 'mailbox';
@import 'search';
.marginLeft {
margin-left: 5px;
}
......@@ -7,11 +7,13 @@ import Constants from '../utils/constants.jsx';
const eventTypes = Constants.EventTypes;
let mailboxesArray = null;
let mailboxexInstances = [];
class MailboxStoreClass extends EventEmitter {
constructor() {
super();
this.current = null;
this.currentPage = {};
}
getMailboxById(id) {
......@@ -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) {
this.current = account;
}
......@@ -54,12 +77,33 @@ class MailboxStoreClass extends EventEmitter {
return false;
}
getPages() {
return this.currentPage;
}
getMailboxes() {
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;
mailboxexInstances = mailboxes.account;
if (page) {
this.currentPage[page] = mailboxes;
console.log(this.currentPage[page]);
}
return true;
}
changeAccount(newAccount) {
......
......@@ -29,6 +29,7 @@ function handleError(methodName, err) {
if (err) {
error.message = err.extra.reason;
error.code = err.extra.code || null;
} else {
error.message = 'Ocurrio un error general';
}
......@@ -111,7 +112,7 @@ export function login(user, password, success, error) {
}
Utils.setCookie('token', zimbra.client.token);
ZimbraStore.setCurrent(zimbra);
window.manager_config.dns.token = Utils.getCookie('token');
return getMe(success, error);
});
}
......@@ -524,9 +525,7 @@ export function search(query, success, error) {
initZimbra().then(
(zimbra) => {
zimbra.directorySearch(
{
query
},
query,
(err, data) => {
if (err) {
const e = handleError('search', err);
......
......@@ -544,3 +544,59 @@ export function getOwners(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