Commit e48dde94 authored by Elias Nahum's avatar Elias Nahum Committed by Juorder Antonio

completed tasks from Trello, for domains, antispam, mailboxes, DLs, import massive, and others.

parent 91a2ec23
......@@ -11,12 +11,26 @@ export function emitStartLoading() {
});
}
export function emitStartTask(params) {
AppDispatcher.handleViewAction({
type: ActionTypes.START_TASK_LOADING,
params
});
}
export function emitEndLoading() {
AppDispatcher.handleViewAction({
type: ActionTypes.END_LOADING
});
}
export function emitEndTask(params) {
AppDispatcher.handleViewAction({
type: ActionTypes.END_TASK_LOADING,
params
});
}
export function emitMessage(attrs) {
AppDispatcher.handleViewAction({
type: ActionTypes.NEW_MESSAGE,
......
......@@ -57,6 +57,7 @@ export default class DistributionLists extends React.Component {
if (domain) {
response.domain = domain;
const dl = DomainStore.getDistributionListById(id, domain);
console.log(domain, dl);
response.distributionsList = dl;
dl.getOwners((error, owners) => {
......@@ -91,6 +92,7 @@ export default class DistributionLists extends React.Component {
}).then((data) => {
DomainStore.setOwners(Utils.getOwners(data.owners));
DomainStore.setMembers(data.distributionsList.members);
this.setState({
distributionsList: data.distributionsList,
members: DomainStore.getMembers(),
......@@ -381,6 +383,8 @@ export default class DistributionLists extends React.Component {
let panelTabs;
let isPrivate = null;
console.log(this.state);
if (this.state.distributionsList && this.state.owners) {
const data = this.state.distributionsList;
const domain = this.state.domain;
......
......@@ -71,7 +71,8 @@ export default class AddAdminModal extends React.Component {
this.props.domain.addAdmin(
user.name,
(error) => {
(error, success) => {
console.log(error, success);
if (error) {
return this.setState({
error: {
......
This diff is collapsed.
......@@ -8,10 +8,14 @@ import MessageBar from '../message_bar.jsx';
import PageInfo from '../page_info.jsx';
import PanelTab from '../panel_tab.jsx';
import Button from '../button.jsx';
import DomainGeneralInfo from './domain_general_info.jsx';
import DomainMailboxPlans from './domain_mailbox_plans.jsx';
import DomainAdmins from './domain_admin_list.jsx';
import DomainDistributionList from './domain_distribution_list.jsx';
import ToggleModalButton from '../toggle_modal_button.jsx';
import MultipleTaskModal from './multiple_task_modal.jsx';
import AntiSpamComponent from './antispam.jsx';
import DomainStore from '../../stores/domain_store.jsx';
......@@ -93,12 +97,42 @@ export default class DomainDetails extends React.Component {
/>
);
const tabTareasMasivas = (
<div>
<ul className='list-inline'>
<li>
<ToggleModalButton
role='button'
className=''
dialogType={MultipleTaskModal}
dialogProps={{
data: domain
}}
key='change-passwd-import'
>
{'Mensaje fuera de Oficina'}
</ToggleModalButton>
</li>
</ul>
</div>
);
const tabAntiSpam = (
<div>
<AntiSpamComponent
data={this.state.domain}
/>
</div>
);
const panelTabs = (
<PanelTab
tabNames={['Administradores', 'Listas De Distribución']}
tabNames={['Administradores', 'AntiSpam', 'Listas De Distribución', 'Tareas Masivas']}
tabs={{
administradores: tabAdmin,
listas_de_distribución: tabDistribution
antispam: tabAntiSpam,
listas_de_distribución: tabDistribution,
tareas_masivas: tabTareasMasivas
}}
location={this.props.location}
/>
......@@ -113,6 +147,13 @@ export default class DomainDetails extends React.Component {
{message}
<div className='content animate-panel'>
<div className='row'>
<div className='layout-back clearfix'>
<div className='back-left backstage'>
<div className='backbg'></div>
</div>
<div className='back-right backstage'>
<div className='backbg'></div>
</div>
<div className='col-md-6 central-content'>
<DomainGeneralInfo
domain={domain}
......@@ -128,6 +169,7 @@ export default class DomainDetails extends React.Component {
/>
</div>
</div>
</div>
<div className='row'>
<div className='col-md-12 panel-with-tabs'>
{panelTabs}
......
// Copyright (c) 2016 ZBox, Spa. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {Modal} from 'react-bootstrap';
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';
export default class MultipleTaskModal extends React.Component {
constructor(props) {
super(props);
this.onSubmit = this.onSubmit.bind(this);
this.getOwnAccounts = this.getOwnAccounts.bind(this);
this.handleChangeDate = this.handleChangeDate.bind(this);
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);
}
onSubmit() {
const accounts = this.state.accounts.account;
const domain = this.props.data;
const total = accounts.length;
const collection = [];
GlobalActions.emitStartTask({
origin: 'Dominio - Tareas Masivas',
id: 'dominio-massive-task',
action: `Asignando mensaje masivo fuera de oficina a ${total}`
});
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;
} else {
attrs.zimbraPrefOutOfOfficeReplyEnabled = isEnabled.toString().toUpperCase();
}
accounts.forEach((account) => {
collection.push(Client.modifyAccountByBatch(account.id, attrs));
});
Client.batchRequest(collection, () => {
GlobalActions.emitEndTask({
id: 'dominio-massive-task',
toast: {
message: `Se han agregado el mensaje fuera de oficina con exito a las ${total} casillas del dominio: ${domain.name}`,
title: 'Dominio - Mensaje Masivo'
}
});
if (this.props.show) {
this.props.onHide();
}
}, (err) => {
console.log('err',err);
if (this.props.show) {
this.props.onHide();
}
});
}
getOwnAccounts() {
const domain = this.props.data;
new Promise((resolve, reject) => {
Client.getAllAccounts({
domain: domain.name
}, (success) => {
return resolve(success);
}, (err) => {
return reject(err);
});
}).then((res) => {
this.setState({
loaded: true,
accounts: res
});
}).catch((error) => {
console.log('err', error);
}).finally(() => {
});
}
componentDidMount() {
this.getOwnAccounts();
}
render() {
let content = null;
if (this.state.loaded) {
content = (
<form
className='simple_form form-horizontal mailbox-form'
id='createAccount'
>
<div className='form-group string'>
<label className='string required col-sm-3 control-label'>
{'Habilitado'}
</label>
<div className='col-sm-8'>
<label className='radio-inline pretty-input'>
<div className='pretty-checkbox'>
<input
type='checkbox'
className='pretty'
ref='zimbraPrefOutOfOfficeReplyEnabled'
/>
<span></span>
</div>
</label>
</div>
</div>
<div className='form-group string'>
<label className='string required col-sm-3 control-label'>
{'Termina el'}
</label>
<div className='col-sm-8'>
<DateTimeField
inputFormat='DD/MM/YYYY'
inputProps={
{
id: 'zimbraPrefOutOfOfficeUntilDate',
readOnly: 'readOnly'
}
}
onChange={this.handleChangeDate}
mode={'date'}
/>
<input
type='hidden'
ref='zimbraPrefOutOfOfficeUntilDate'
/>
</div>
</div>
<div className='form-group string'>
<label className='string required col-sm-3 control-label'>
{'Respuesta'}
</label>
<div className='col-sm-8'>
<textarea
name='response'
id='responseBox'
className='form-control'
rows='4'
ref='zimbraPrefOutOfOfficeReply'
>
</textarea>
</div>
</div>
</form>
);
} else {
content = (
<div className='text-center'>
<i className='fa fa-spinner fa-spin fa-3x fa-fw'></i>
<p>Cargando...</p>
</div>
);
}
return (
<Modal
show={this.props.show}
onHide={this.props.onHide}
bsSize={'lg'}
>
<div className='color-line'></div>
<Modal.Header closeButton={true}>
<Modal.Title>
{'Tareas Masivas'}
</Modal.Title>
</Modal.Header>
<Modal.Body>
<div>
{content}
</div>
</Modal.Body>
<Modal.Footer>
<button
type='button'
className='btn btn-default'
onClick={this.props.onHide}
>
{'Cancelar'}
</button>
<button
className='btn btn-info action-massive'
type='button'
onClick={this.onSubmit}
>
{'Guardar'}
</button>
</Modal.Footer>
</Modal>
);
}
}
MultipleTaskModal.propTypes = {
show: React.PropTypes.bool.isRequired,
onHide: React.PropTypes.func.isRequired,
data: React.PropTypes.object
};
This diff is collapsed.
......@@ -5,6 +5,7 @@ import LoadingScreen from './loading_screen.jsx';
import Header from './header.jsx';
import Sidebar from './sidebar.jsx';
import ToastAlert from './toast_alert.jsx';
import ProgressTask from './progress_task.jsx';
import React from 'react';
......@@ -12,6 +13,7 @@ export default class LoggedIn extends React.Component {
render() {
return (
<div>
<ProgressTask/>
<ToastAlert/>
<LoadingScreen/>
<Header/>
......
// Copyright (c) 2016 ZBox, Spa. All Rights Reserved.
// 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 React from 'react';
import PasswordStrengthMeter from 'react-password-strength-meter';
export default class ConfirmDeleteModal extends React.Component {
constructor(props) {
......@@ -13,10 +13,24 @@ export default class ConfirmDeleteModal extends React.Component {
this.handleChangePasswd = this.handleChangePasswd.bind(this);
this.forceLogout = this.forceLogout.bind(this);
this.handlePasswd = this.handlePasswd.bind(this);
this.restart = this.restart.bind(this);
this.state = this.getStateFromStores();
}
restart() {
this.setState({
message: null
});
}
handlePasswd(e) {
const hidePasswd = this.refs.passwdfield;
hidePasswd.value = e.target.value;
}
getStateFromStores() {
const currentUser = UserStore.getCurrentUser();
return {currentUser};
......@@ -30,6 +44,14 @@ export default class ConfirmDeleteModal extends React.Component {
handleChangePasswd() {
if (this.refs.passwdfield.value && this.refs.passwdfield.value.length > 0) {
if (this.refs.passwdfield.value.length < 9) {
return this.setState({
alert: true,
message: 'Su contraseña debe ser mayor a 8 caracteres.',
typeError: 'text-danger'
});
}
this.props.data.setPassword(this.refs.passwdfield.value, () => {
this.setState({
alert: true,
......@@ -69,6 +91,9 @@ export default class ConfirmDeleteModal extends React.Component {
<Modal
show={this.props.show}
onHide={this.props.onHide}
onExit={() => {
this.restart();
}}
>
<div className='color-line'></div>
<Modal.Header closeButton={true}>
......@@ -85,11 +110,26 @@ export default class ConfirmDeleteModal extends React.Component {
</div>
<div className='col-xs-7'>
<input
type='password'
type='hidden'
ref='passwdfield'
className='form-control'
id='passwdfield'
/>
<PasswordStrengthMeter
passwordText=''
className='form-control passwd-field'
hasLabel={false}
hasSuggestion={false}
hasWarning={true}
warning='Su contraseña debe ser mayor a 8 caracteres.'
onChange={this.handlePasswd}
strength={{
0: 'Su contraseña es muy debil',
1: 'Debe incrementar la dificultad de su contraseña',
2: 'Su contraseña es relativamente fuerte',
3: 'Su contraseña es fuerte'
}}
/>
</div>
<div className='col-xs-12 text-center'>
<br/>
......
import $ from 'jquery';
import React from 'react';
import PasswordStrengthMeter from 'react-password-strength-meter';
import Panel from '../panel.jsx';
import Button from '../button.jsx';
import MessageBar from '../message_bar.jsx';
......@@ -11,6 +12,7 @@ import * as Client from '../../utils/client.jsx';
import * as Utils from '../../utils/utils.jsx';
import EventStore from '../../stores/event_store.jsx';
import MailboxStore from '../../stores/mailbox_store.jsx';
import DomainStore from '../../stores/domain_store.jsx';
import Constants from '../../utils/constants.jsx';
......@@ -25,11 +27,19 @@ export default class CreateMailBox extends React.Component {
this.showMessage = this.showMessage.bind(this);
this.handleRadioChanged = this.handleRadioChanged.bind(this);
this.controllerDataList = this.controllerDataList.bind(this);
this.handlePasswd = this.handlePasswd.bind(this);
this.reset = null;
this.state = {};
}
handlePasswd(e) {
const hidePasswd = this.refs.passwd;
hidePasswd.value = e.target.value;
}
showMessage(attrs) {
this.setState({
error: attrs.message,
......@@ -43,6 +53,8 @@ export default class CreateMailBox extends React.Component {
Utils.validateInputRequired(this.refs).then(() => {
// here assign missing properties.
const domain = document.querySelector('input[list=\'domain\']');
const passwd = this.refs.passwd.value;
const maskPasswd = document.getElementById('password');
if (domain.value === '') {
GlobalActions.emitMessage({
......@@ -55,6 +67,17 @@ export default class CreateMailBox extends React.Component {
return false;
}
if (passwd.length < 9) {
GlobalActions.emitMessage({
message: 'La contraseña debe ser mayor a 8 caracteres, verifique por favor.',
typeError: messageType.ERROR
});
maskPasswd.focus();
return false;
}
const email = this.refs.mail.value + '@' + domain.value;
//falta campo de tipo de casilla
......@@ -68,7 +91,7 @@ export default class CreateMailBox extends React.Component {
Client.createAccount(
email,
this.refs.passwd.value,
passwd,
attrs,
(data) => {
// reset form when all is ok
......@@ -77,6 +100,8 @@ export default class CreateMailBox extends React.Component {
MailboxStore.setMailbox(data);
//return Utils.handleLink(event, `/mailboxes/${data.id}`, this.props.location);
GlobalActions.emitMessage({
message: 'Se ha creado su cuenta con éxito.',
typeError: messageType.SUCCESS
......@@ -145,6 +170,24 @@ export default class CreateMailBox extends React.Component {
return true;
});
if (this.props.params.id) {
let defaultDomain = null;
if (DomainStore.getCurrent()) {
defaultDomain = DomainStore.getCurrent();
}
if (!defaultDomain) {
const currentDomainId = this.props.params.id;
defaultDomain = response.domains.domain.find((domain) => {
if (currentDomainId === domain.id) {
return domain;
}
});
}
response.currentDomain = defaultDomain.name;
}
this.setState(response);
GlobalActions.emitEndLoading();
......@@ -259,6 +302,7 @@ export default class CreateMailBox extends React.Component {
className='form-control'
placeholder='Dominio'
getController={this.controllerDataList}
initialFilter={this.state.currentDomain}
/>
</div>
</div>
......@@ -352,13 +396,28 @@ export default class CreateMailBox extends React.Component {
<div className='col-sm-8'>
<input
type='password'
type='hidden'
className='form-control'
data-required='true'
data-message='La contraseña de su casilla es requerida, verifique por favor.'
ref='passwd'
id='passwdMeter'
/>
<PasswordStrengthMeter
passwordText=''
className='form-control passwd-field'
hasLabel={false}
hasSuggestion={false}
hasWarning={true}
warning='Su contraseña debe ser mayor a 8 caracteres.'
onChange={this.handlePasswd}
strength={{
0: 'Su contraseña es muy debil',
1: 'Debe incrementar la dificultad de su contraseña',
2: 'Su contraseña es relativamente fuerte',
3: 'Su contraseña es fuerte'
}}
/>
</div>
</div>
......
......@@ -29,6 +29,7 @@ export default class EditMailBox extends React.Component {
this.getMailbox = this.getMailbox.bind(this);
this.fillForm = this.fillForm.bind(this);
this.showMessage = this.showMessage.bind(this);
this.handleRenameAccount = this.handleRenameAccount.bind(this);
this.state = {};
}
......@@ -44,12 +45,18 @@ export default class EditMailBox extends React.Component {
this.refs.zimbraCOSId.value = val;
}
handleEdit(e) {
e.preventDefault();
Utils.toggleStatusButtons('.action-button', true);
handleEnabledRename() {
const selfButton = this.refs.rename;
const inputs = document.querySelectorAll('.action-rename');
const email = inputs[0];
const domain = inputs[1];
Utils.validateInputRequired(this.refs).then(() => {
const domain = document.querySelector('input[list=\'domain\']');
if (selfButton.hasAttribute('data-rename')) {
selfButton.removeAttribute('data-rename');
selfButton.innerHTML = 'Actualizar';
Utils.toggleStatusButtons('.action-rename', false);
return false;
}
if (domain.value === '') {
GlobalActions.emitMessage({
......@@ -62,8 +69,95 @@ export default class EditMailBox extends React.Component {
return false;
}
const email = this.refs.mail.value + '@' + domain.value;
if (email.value === '') {
GlobalActions.emitMessage({
message: 'El campo mail es requerido, verifique por favor.',
typeError: messageType.ERROR
});
email.focus();
return false;
}
const mail = email.value + '@' + domain.value;
const isEmail = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
if (!isEmail.test(mail)) {
GlobalActions.emitMessage({
message: 'El email no tiene el formato correcto, verifique por favor.',
typeError: messageType.ERROR
});
return false;
}
this.handleRenameAccount(mail);
}
handleRenameAccount(email) {
const account = MailboxStore.getCurrent();
if (account) {
const oldName = this.refs.rename.innerHTML;
this.refs.rename.innerHTML = 'Actualizando';
Utils.toggleStatusButtons('.change-email', true);
return account.rename(email, (error, success) => {
if (error) {
this.setState({
data: account
});
this.refs.rename.innerHTML = oldName;
Utils.toggleStatusButtons('.change-email', false);
return GlobalActions.emitMessage({
message: error.extra.reason,
typeError: messageType.ERROR
});
}
let newAccount = MailboxStore.changeAccount(success);
if (!newAccount) {
newAccount = success;
}
this.setState({
data: newAccount
});
this.refs.rename.innerHTML = 'Renombrar';
this.refs.rename.setAttribute('data-rename', 'true');
Utils.toggleStatusButtons('.change-email', false);
return GlobalActions.emitMessage({
message: 'Se ha modificado el nombre de su cuenta éxitosamente',
typeError: messageType.SUCCESS
});
});
}
GlobalActions.emitMessage({
message: 'Error, no existe instancia de la casilla.',
typeError: messageType.ERROR
});
}
componentDidUpdate() {
const button = this.refs.rename;
if (button.hasAttribute('data-rename')) {
Utils.toggleStatusButtons('.action-rename', true);
}
}
handleEdit(e) {
e.preventDefault();
Utils.toggleStatusButtons('.action-button', true);
Utils.validateInputRequired(this.refs).then(() => {
// fill new attrs
const attrs = {
givenName: this.refs.givenName.value,
......@@ -89,29 +183,7 @@ export default class EditMailBox extends React.Component {
}).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
});
});
Utils.handleLink(e, `/mailboxes/${this.props.params.id}`, this.props.location);
}).catch((error) => {
GlobalActions.emitMessage({
message: error.message,
......@@ -166,6 +238,7 @@ export default class EditMailBox extends React.Component {
promises.push(domains, cos);
Promise.all(promises).then((result) => {
MailboxStore.setCurrent(data);
this.setState({
data,
domains: result.shift().domain,
......@@ -174,7 +247,7 @@ export default class EditMailBox extends React.Component {
Utils.toggleStatusButtons('.action-save', false);
}).catch((error) => {
GlobalActions.emitMessage({
error: error.message,
message: error.message,
typeError: error.type
});
}).finally(() => {
......@@ -218,15 +291,19 @@ export default class EditMailBox extends React.Component {
promises.push(mailbox, doms, cos);
Promise.all(promises).then((result) => {
const account = result.shift();
this.setState({
data: result.shift(),
data: account,
domains: result.shift().domain,
cos: Utils.getEnabledPlansByCos(result.shift())
});
Utils.toggleStatusButtons('.action-save', false);
MailboxStore.setCurrent(account);
}).catch((error) => {
GlobalActions.emitMessage({
error: error.message,
message: error.message,
typeError: error.type
});
}).finally(() => {
......@@ -355,7 +432,7 @@ export default class EditMailBox extends React.Component {
<DataList
list='domain'
options={domains}
className='form-control'
className='form-control action-rename'
placeholder='Dominio'
initialFilter={currentDomain}
/>
......@@ -382,13 +459,25 @@ export default class EditMailBox extends React.Component {
<div className='input-group'>
<input
type='text'
className='form-control'
className='form-control action-rename'
ref='mail'
data-required='true'
placeholder='Mail'
/>
<span className='input-group-addon'>{'@'}</span>
{datalist}
<span className='input-group-btn'>
<button
className='btn btn-default change-email'
type='button'
ref='rename'
data-rename='true'
onClick={() => {
this.handleEnabledRename();
}}
>
Renombrar
</button>
</span>
</div>
</div>
</div>
......@@ -504,7 +593,7 @@ export default class EditMailBox extends React.Component {
props: {
className: 'btn btn-default btn-xs action-button',
onClick: (e) => {
Utils.handleLink(e, '/mailboxes', this.props.location);
Utils.handleLink(e, `/mailboxes/${this.props.params.id}`, this.props.location);
}
}
},
......
......@@ -20,17 +20,28 @@ import * as GlobalActions from '../../action_creators/global_actions.jsx';
import * as Utils from '../../utils/utils.jsx';
import Constants from '../../utils/constants.jsx';
import ToggleModalButton from '../toggle_modal_button.jsx';
import ImportMassiveModal from '../import_massive_modal.jsx';
import DomainStore from '../../stores/domain_store.jsx';
const QueryOptions = Constants.QueryOptions;
const messageType = Constants.MessageType;
import ZimbraStore from '../../stores/zimbra_store.jsx';
export default class Mailboxes extends React.Component {
constructor(props) {
super(props);
this.showMessage = this.showMessage.bind(this);
this.refreshAllAccounts = this.refreshAllAccounts.bind(this);
this.handleFilterMailbox = this.handleFilterMailbox.bind(this);
this.handleChangeFilter = this.handleChangeFilter.bind(this);
const page = parseInt(this.props.location.query.page, 10) || 1;
this.mailboxes = null;
this.status = '';
this.cos = null;
this.state = {
page,
......@@ -38,6 +49,69 @@ export default class Mailboxes extends React.Component {
};
}
handleChangeFilter(e) {
const selected = e.target.value;
const cos = Utils.getEnabledPlansByCos(ZimbraStore.getAllCos());
if (e.target.className.indexOf('plans') > -1) {
this.cos = cos[selected];
}
if (e.target.className.indexOf('status') > -1) {
this.status = selected;
}
const data = Object.assign({}, this.mailboxes);
const arrayFiltered = data.account.filter((strArray) => {
const status = this.status === '' ? strArray.attrs.zimbraAccountStatus : this.status;
const plan = this.cos ? this.cos : strArray.attrs.zimbraCOSId;
if (strArray.attrs.zimbraAccountStatus === status && strArray.attrs.zimbraCOSId === plan) {
return strArray;
}
return false;
});
data.account = arrayFiltered;
data.total = arrayFiltered.length;
const tables = this.buildTableFromData(data, ['Todas', 'Bloqueadas']);
return this.setState({
data: tables
});
}
handleFilterMailbox(e, info) {
const search = e.target.value;
const data = Object.assign({}, info);
const arrayFiltered = data.account.filter((strArray) => {
if (this.status === '') {
if (strArray.name.match(search)) {
return strArray;
}
}
if (strArray.name.match(search) && strArray.attrs.zimbraAccountStatus === this.status) {
return strArray;
}
return false;
});
data.account = arrayFiltered;
data.total = arrayFiltered.length;
const tables = this.buildTableFromData(data, ['Todas', 'Bloqueadas']);
return this.setState({
data: tables
});
}
showMessage(attrs) {
this.setState({
error: attrs.error,
......@@ -122,6 +196,7 @@ export default class Mailboxes extends React.Component {
return Client.getAllAccounts(attrs, (success) => {
MailboxStore.setMailboxes(success);
this.mailboxes = this.mailboxes = MailboxStore.getMailboxes();
return resolve(success);
}, (error) => {
return reject(error);
......@@ -143,10 +218,11 @@ export default class Mailboxes extends React.Component {
}
return this.setState({
domainNotFound: domainName
notMatches: true,
domain: domainName
});
}).catch(() => {
//console.log(error);
console.log('error',error);
}).finally(() => {
GlobalActions.emitEndLoading();
});
......@@ -163,15 +239,33 @@ export default class Mailboxes extends React.Component {
return this.getAccounts();
}
refreshAllAccounts() {
const mailboxes = MailboxStore.getMailboxes();
const tables = this.buildTableFromData(mailboxes, ['Todas', 'Bloqueadas']);
if (tables.lockedAlert) {
GlobalActions.emitMessage({
error: tables.lockedAlert.message,
typeError: messageType.LOCKED
});
}
this.setState({
data: tables
});
}
componentDidMount() {
$('#sidebar-mailboxes').addClass('active');
EventStore.addMessageListener(this.showMessage);
MailboxStore.addListenerAddMassive(this.refreshAllAccounts);
const domainId = this.props.params.domain_id;
this.getAllMailboxes(domainId);
}
componentWillUnmount() {
EventStore.removeMessageListener(this.showMessage);
MailboxStore.removeListenerAddMassive(this.showMessage);
$('#sidebar-mailboxes').removeClass('active');
}
......@@ -235,6 +329,16 @@ export default class Mailboxes extends React.Component {
);
}
if (Array.isArray(rows) && rows.length < 1) {
return (
<div className='text-center'>
<h4>
No existen resultados para su búsqueda
</h4>
</div>
);
}
return (
<div
key='mailbox'
......@@ -264,14 +368,16 @@ export default class Mailboxes extends React.Component {
);
}
insertToPanel(table, id, btns) {
insertToPanel(table, id, btns, filter) {
const btn = btns || [];
const getFilter = filter || null;
return (
<Panel
children={table}
key={id}
btnsHeader={btn}
filter={getFilter}
/>
);
}
......@@ -326,6 +432,21 @@ export default class Mailboxes extends React.Component {
},
label: icon
},
{
setComponent: (
<ToggleModalButton
role='button'
className='btn btn-info hide-xs hide-sm'
dialogType={ImportMassiveModal}
dialogProps={{
data: this.state.data
}}
key='change-passwd-import'
>
{'Importar'}
</ToggleModalButton>
)
},
{
props: {
className: 'btn btn-success',
......@@ -352,8 +473,37 @@ export default class Mailboxes extends React.Component {
};
}
const filter = (
<div>
<div className='input-group pull-left'>
<select
className='form-control status'
onChange={this.handleChangeFilter}
>
<option value=''>Todas</option>
<option value='active'>Activa</option>
<option value='locked'>Inactiva</option>
<option value='lockedout'>Bloqueada</option>
<option value='closed'>Cerradas</option>
</select>
</div>
<div className='input-group'>
<select
className='form-control plans'
onChange={this.handleChangeFilter}
>
<option value=''>Todoas los planes</option>
<option value='basic'>Básico</option>
<option value='professional'>Profesional</option>
<option value='premium'>Premium</option>
</select>
</div>
</div>
);
const tableActive = this.makeTable(activeAccounts, activePagination);
const panelActive = this.insertToPanel(tableActive, 'panel-all', btn);
const panelActive = this.insertToPanel(tableActive, 'panel-all', btn, filter);
// create structure html for all locked accounts
const tableLocked = this.makeTable(lockedAccounts, lockedPagination);
......@@ -381,6 +531,7 @@ export default class Mailboxes extends React.Component {
render() {
let message = null;
let content = null;
if (this.state.error) {
message = (
......@@ -392,13 +543,17 @@ export default class Mailboxes extends React.Component {
);
}
let content = (
if (this.state.notMatches) {
const domain = (this.state.domain) ? `para el dominio: ${this.state.domain}` : '';
content = (
<div className='text-center'>
<h4>
No se han encontrado casillas para el dominio : {this.state.domainNotFound}
{`No se han encontrado resultados ${domain}`}
</h4>
</div>
);
}
const pagelInfo = (
<PageInfo
titlePage='Casillas'
......@@ -417,6 +572,7 @@ export default class Mailboxes extends React.Component {
onClick={this.handleTabChanged}
/>
);
}
return (
......
......@@ -88,9 +88,20 @@ export default class MailboxDetails extends React.Component {
}
}
account.viewMailPath(global.window.manager_config.webmailLifetime, (error, res) => {
if (res) {
return this.setState({
data: account,
alias: items,
webmail: `${global.window.manager_config.webMailUrl}${res}`
});
}
this.setState({
data: account,
alias: items
alias: items,
webmail: false
});
});
GlobalActions.emitEndLoading();
......@@ -112,9 +123,20 @@ export default class MailboxDetails extends React.Component {
}
}
result.viewMailPath(global.window.manager_config.webmailLifetime, (error, res) => {
if (res) {
return this.setState({
data: result,
alias: items,
webmail: `${global.window.manager_config.webMailUrl}${res}`
});
}
this.setState({
data: result,
alias: items
alias: items,
webmail: false
});
});
}).catch((error) => {
GlobalActions.emitMessage({
......@@ -314,14 +336,29 @@ export default class MailboxDetails extends React.Component {
}
];
if (this.state.webmail) {
btnsStats = [
{
props: {
className: 'btn btn-xs btn-default action-info-btns',
target: '_blank',
href: this.state.webmail
},
label: 'Ver Correos'
}
];
} else {
btnsStats = [
{
props: {
className: 'btn btn-xs btn-default action-info-btns'
className: 'btn btn-xs btn-default disabled',
title: 'Hubo un error al obtener el acceso al mail',
disabled: 'disabled'
},
label: 'Ver Correos'
}
];
}
const formAutoResp = (
<FormVacacionesMailbox data={this.state.data}/>
......
......@@ -30,18 +30,23 @@ export default class BlockGeneralInfoMailbox extends React.Component {
this.date = Utils.dateFormatted(this.props.data.attrs.zimbraCreateTimestamp);
switch (this.props.data.attrs.zimbraAccountStatus) {
case 'inactive':
this.status = 'Desactivada';
this.className = 'btn-default mailbox-status';
break;
case 'locked':
case 'lockedout':
this.status = 'Bloqueada';
this.className = 'btn-primary2 mailbox-status';
this.className = 'label-locked mailbox-status';
break;
default:
case 'active':
this.status = 'Activa';
this.className = 'btn-info mailbox-status';
this.className = 'label-success mailbox-status';
break;
case 'closed':
this.status = 'Cerrada';
this.className = 'label-default mailbox-status';
break;
case 'locked':
this.status = 'Inactiva';
this.className = 'label-warning mailbox-status';
break;
default:
}
if (this.props.data.attrs.zimbraLastLogonTimestamp) {
......@@ -90,7 +95,7 @@ export default class BlockGeneralInfoMailbox extends React.Component {
<div className='col-xs-6'>
<div>
<p>
<span className='center-block'>Últimas Conexión</span>
<span className='center-block'>Última Conexión</span>
<strong>{this.lastConection}</strong>
</p>
</div>
......
......@@ -22,8 +22,8 @@ export default class Panel extends React.Component {
panelHeader = (
<div className='panel-heading hbuilt clearfix'>
<div className='pull-right'>{btns}</div>
<div className='heading-buttons'>
{this.props.title}
<div className='heading-buttons pull-left'>
{this.props.title || this.props.filter}
</div>
</div>
);
......@@ -47,7 +47,8 @@ Panel.propTypes = {
title: React.PropTypes.string,
classHeader: React.PropTypes.string,
error: React.PropTypes.element,
children: React.PropTypes.any
children: React.PropTypes.any,
filter: React.PropTypes.element
};
Panel.defaultProps = {
......
......@@ -13,6 +13,15 @@ export default class Panel extends React.Component {
};
}
componentWillReceiveProps(nextProps) {
if (Object.keys(nextProps.tabs)[0] !== Object.keys(this.props.tabs)[0]) {
const tab = this.props.location.query.tab || Object.keys(nextProps.tabs)[0];
this.setState({
tab
});
}
}
changeTab(e, tabName) {
e.preventDefault();
......
// Copyright (c) 2016 ZBox, Spa. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import EventStore from '../stores/event_store.jsx';
import * as GlobalActions from '../action_creators/global_actions.jsx';
export default class ProgressTask extends React.Component {
constructor(props) {
super(props);
this.showTasks = this.showTasks.bind(this);
this.removeTask = this.removeTask.bind(this);
this.tasks = [];
this.state = {};
}
componentWillUnmount() {
EventStore.removeTaskSListener(this.showTasks);
EventStore.removeEndTaskSListener(this.removeTask);
}
componentDidMount() {
EventStore.addTaskSListener(this.showTasks);
EventStore.addEndTaskSListener(this.removeTask);
}
removeTask(params) {
if (this.tasks.length > 0) {
const arrTasks = this.tasks;
const length = arrTasks.length;
for (let i = 0; i < length; i++) {
if (arrTasks[i].id === params.id) {
this.tasks.splice(i, 1);
EventStore.emitToast({
type: 'success',
title: params.toast.title,
body: params.toast.message,
options: {
timeOut: 10000,
extendedTimeOut: 5000,
closeButton: true
}
});
break;
}
}
}
if (this.tasks.length < 1) {
return this.setState({
show: null
});
}
return this.setState({
tasks: this.tasks,
total: this.tasks.length
});
}
showTasks(params) {
this.tasks.push(params);
this.setState({
show: true,
tasks: this.tasks,
total: this.tasks.length
});
}
render() {
let tasks = null;
let show = null;
let message = 'Acciones en ejecución';
if (this.state.show) {
show = 'active';
}
if (this.state.tasks) {
const taskList = this.state.tasks;
tasks = [];
taskList.forEach((task, index) => {
tasks.push((
<ul
key={`ul-${index}`}
>
<li>{`${task.origin} - ${task.action}`}</li>
</ul>
));
});
}
if (this.state.total) {
const multiple = (this.state.total > 1) ? 'tareas' : 'tarea';
message = `${this.state.total} ${multiple} en ejecución`;
}
return (
<div className={`progress manager-progress ${show}`}>
<div className='taskboard alert-success'>
<div className='wrap-task'>
{tasks}
</div>
</div>
<div className={`progress-bar manager-task-bar progress-bar-striped ${show}`}>
{message}
</div>
</div>
);
}
}
ProgressTask.defaultProps = {
};
ProgressTask.propTypes = {
children: React.PropTypes.oneOfType([
React.PropTypes.arrayOf(React.PropTypes.element),
React.PropTypes.element
])
};
import React from 'react';
export default class SelectCol extends React.Component {
constructor(props) {
super(props);
this.options = this.props.options;
this.disabledOptions = this.props.disabledOptions;
this.current = this.props.selected;
this.state = {
options: this.options
};
}
handleSelectChange(e, id) {
e.preventDefault();
if (this.props.onSelected) {
const option = e.target;
let selected = option.options[option.options.selectedIndex].text;
const restart = option.options[option.options.selectedIndex].hasAttribute('data-main');
if (selected) {
if (restart) {
selected = {
restart: this.current
};
this.current = null;
} else {
this.current = selected;
}
return this.props.onSelected(e, selected, id);
}
return null;
}
return null;
}
componentWillUnmount() {
this.setState({
options: null
});
}
render() {
let options = null;
const current = this.current;
if (this.state.options) {
const optionElement = this.state.options;
options = [];
options.push((
<option
key='header-option'
data-main={'true'}
>
{'Columna'}
</option>
));
for (const option in optionElement) {
if (optionElement.hasOwnProperty(option)) {
const isDisabled = (this.disabledOptions[option]) ? 'disabled' : null;
options.push((
<option
value={optionElement[option]}
key={`${option}-option`}
disabled={isDisabled}
>
{option}
</option>
));
}
}
}
return (
<select
{...this.props.selectAttrs}
onChange={(e) => {
this.handleSelectChange(e, this.props.id);
}}
defaultValue={current}
>
{options}
</select>
);
}
}
SelectCol.propTypes = {
options: React.PropTypes.object.isRequired,
selectAttrs: React.PropTypes.object,
onSelected: React.PropTypes.func,
disabledOptions: React.PropTypes.object,
selected: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.bool
]),
id: React.PropTypes.any.isRequired
};
SelectCol.defaultProps = {
options: []
};
......@@ -3,12 +3,14 @@
"zimbraUrl": "http://zimbra.zboxapp.dev:8000/service/admin/soap",
"zimbraProxy": "https://zimbra.zboxapp.dev:7071",
"dnsApiUrl": "http://zimbra.zboxapp.dev:3000",
"webMailUrl": "https://zimbra.zboxapp.dev",
"plans": {
"basic": true,
"premium": true,
"professional": true,
"default": false
},
"webmailLifetime": 3600,
"companiesEndPoints": {
"list": "http://zimbra.zboxapp.dev:8001/list",
"detail": "http://zimbra.zboxapp.dev:8001/company/{id}",
......
......@@ -135,6 +135,10 @@ function renderRootComponent() {
path='domains/:id'
component={DomainDetails}
/>
<Route
path='domains/:id/mailboxes/new'
component={CreateMailBox}
/>
<Route
path='domains/:id/edit'
component={EditDomains}
......
.wrapper-importer {
padding: 10px 0;
}
.col-import {
float: left;
max-height: 300px;
overflow: auto;
padding: 5px;
width: 20%;
.wrap-border-col {
&.missing-option {
border: 2px solid $red;
.list-attr {
background: $bg-import-error;
}
}
&.ok-option {
border: 2px solid $border-color-ok;
.list-attr {
background: $bg-import-ok;
}
}
.list-attr {
margin-bottom: 0;
overflow: hidden;
padding: 2px;
li {
border-top: 1px dotted $white;
overflow: hidden;
padding: 5px 0;
text-overflow: ellipsis;
&:last-child {
border-bottom: 1px dotted $white;
}
}
}
}
}
......@@ -7,11 +7,13 @@
@import 'grid';
@import 'icheck';
@import 'lists';
@import 'importer';
@import 'loader';
@import 'modal';
@import 'panel_add';
@import 'panels';
@import 'progress_bar';
@import 'progress_task';
@import 'tabs';
@import 'tooltip';
@import 'tour';
......
.progress.manager-progress {
box-shadow: 0 0 5px 0 $black;
height: auto;
left: 0;
margin: auto;
position: absolute;
right: 0;
transform: translateY(-100%);
transition: transform .5s;
width: 80%;
z-index: 1;
&.active {
transform: translateY(0%);
}
&:hover {
.taskboard {
max-height: 200px;
}
}
.wrap-task {
padding: 10px 0;
}
.taskboard {
max-height: 0;
overflow: hidden;
height: 100%;
transition: max-height 1s;
.alert {
margin-bottom: 0;
}
ul {
margin: 0;
}
}
.progress-bar.manager-task-bar {
background-color: $account-link-color;
color: $white;
line-height: 1;
padding: 3px 0;
text-align: center;
width: 100%;
}
}
......@@ -59,3 +59,46 @@
font-size: 22px;
font-weight: 600;
}
.layout-back {
overflow: hidden;
position: relative;
.hpanel {
.panel-body {
background: transparent;
border-bottom-color: transparent;
}
.panel-heading {
background: transparent;
}
}
.backstage {
height: 100%;
margin-top: -25px;
overflow: hidden;
padding: 0 15px;
position: absolute;
width: 50%;
&.back-left {
left: 0;
}
&.back-right {
right: 0;
}
.backbg {
background: $white;
border-bottom: 1px solid $color-new-fields;
border-left: 1px solid $color-new-fields;
border-right: 1px solid $color-new-fields;
height: 100%;
position: relative;
width: 100%;
}
}
}
......@@ -25,3 +25,10 @@
.label-locked {
background: $color-violet;
}
.passwd-field {
+ meter {
margin-top: 5px;
width: 100%;
}
}
......@@ -87,3 +87,9 @@ $account-link-color: #337ab7;
//Panel add
$color-new-fields: #e4e5e7;
// importer colors
$bg-import-ok: rgba(78, 165, 224, .2);
$border-color-ok: #4ea5e0;
$bg-import-error: #ffe8e8;
......@@ -56,6 +56,30 @@ class EventStoreClass extends EventEmitter {
removeToastListener(callback) {
this.removeListener(eventTypes.NEW_TOAST_EVENT, callback);
}
emitTask(params) {
this.emit(eventTypes.START_TASK_LOADING_EVENT, params);
}
emitEndTask(params) {
this.emit(eventTypes.END_TASK_LOADING_EVENT, params);
}
addEndTaskSListener(params) {
this.on(eventTypes.END_TASK_LOADING_EVENT, params);
}
addTaskSListener(callback) {
this.on(eventTypes.START_TASK_LOADING_EVENT, callback);
}
removeTaskSListener(callback) {
this.removeListener(eventTypes.START_TASK_LOADING_EVENT, callback);
}
removeEndTaskSListener(params) {
this.removeListener(eventTypes.END_TASK_LOADING_EVENT, params);
}
}
var EventStore = new EventStoreClass();
......@@ -77,6 +101,12 @@ EventStore.dispatchToken = AppDispatcher.register((payload) => {
case ActionTypes.NEW_TOAST:
EventStore.emitToast(action.message);
break;
case ActionTypes.START_TASK_LOADING:
EventStore.emitTask(action.params);
break;
case ActionTypes.END_TASK_LOADING:
EventStore.emitEndTask(action.params);
break;
default:
}
});
......
......@@ -2,6 +2,9 @@
// See LICENSE.txt for license information.
import EventEmitter from 'events';
import Constants from '../utils/constants.jsx';
const eventTypes = Constants.EventTypes;
let mailboxesArray = null;
......@@ -154,6 +157,20 @@ class MailboxStoreClass extends EventEmitter {
return false;
}
// Declare here all events that fired when something happens
emitAddMassive() {
this.emit(eventTypes.MAILBOX_ADD_MASSIVE_EVENT);
}
addListenerAddMassive(callback) {
this.on(eventTypes.MAILBOX_ADD_MASSIVE_EVENT, callback);
}
removeListenerAddMassive(callback) {
this.removeListener(eventTypes.MAILBOX_ADD_MASSIVE_EVENT, callback);
}
}
const MailboxStore = new MailboxStoreClass();
......
......@@ -266,6 +266,25 @@ export function modifyDomain(domain, success, error) {
);
}
export function modifyDomainByAttrs(domainId, attrs, success, error) {
initZimbra().then(
(zimbra) => {
zimbra.modifyDomain(domainId, attrs, (err, data) => {
if (err) {
const e = handleError('modifyDomainByAttrs', err);
return error(e);
}
return success(data);
});
},
(err) => {
const e = handleError('modifyDomainByAttrs', err);
return error(e);
}
);
}
export function addDistributionList(name, attrs, success, error) {
initZimbra().then(
(zimbra) => {
......@@ -361,6 +380,20 @@ export function createAccount(mail, passwd, attrs, success, error) {
);
}
export function createAccountByBatch(mail, passwd, attrs) {
return ZimbraStore.getCurrent().createAccount(mail, passwd, attrs);
}
export function modifyAccountByBatch(id, attrs) {
//window.Zimbra.modifyAccount(temp1.account[0].id, {sn: 'nuevo sn'});
return ZimbraStore.getCurrent().modifyAccount(id, attrs);
}
export function buildAccountByObject(account) {
const zimbra = ZimbraStore.getCurrent();
return zimbra.dictionary.classFactory('account', account, zimbra.client);
}
export function modifyAccount(idZimbra, attrs, success, error) {
initZimbra().then(
(zimbra) => {
......@@ -557,6 +590,25 @@ export function getAllCos(success, error) {
);
}
export function getAllDistributionLists(query, success, error) {
initZimbra().then(
(zimbra) => {
zimbra.getAllDistributionLists((err, data) => {
if (err) {
const e = handleError('getAllDistributionLists', err);
return error(e);
}
return success(data);
}, query);
},
(err) => {
const e = handleError('getAllDistributionLists', err);
return error(e);
}
);
}
export function getDistributionList(id, success, error) {
initZimbra().then(
(zimbra) => {
......
......@@ -7,6 +7,8 @@ export default {
ActionTypes: keyMirror({
START_LOADING: null,
END_LOADING: null,
START_TASK_LOADING: null,
END_TASK_LOADING: null,
USER_CHANGED: null,
RECEIVED_ERROR: null,
NEW_MESSAGE: null,
......@@ -24,9 +26,12 @@ export default {
ACCOUNT_CHANGE_EVENT: null,
START_LOADING_EVENT: null,
END_LOADING_EVENT: null,
START_TASK_LOADING_EVENT: null,
END_TASK_LOADING_EVENT: null,
USER_CHANGE_EVENT: null,
NEW_MESSAGE_EVENT: null,
NEW_TOAST_EVENT: null
NEW_TOAST_EVENT: null,
MAILBOX_ADD_MASSIVE_EVENT: null
}),
MessageType: keyMirror({
......
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