Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NEW] Contextual bar mail messages #9510

Merged
merged 4 commits into from
Jan 26, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,31 +1,49 @@
<template name="mailMessagesInstructions">
<main class="rc-user-info__scroll">
<div class="rc-input rc-input--usernames">
<label class="rc-input__label">
<div class="rc-input__title">{{_ "To_users"}}</div>
<div class="rc-input__wrapper">
<div class="rc-input__icon">
{{> icon block="rc-input__icon-svg" icon="at"}}
{{#if selectedMessages}}
<div class="mail-messages__instructions mail-messages__instructions--selected">
<div class="mail-messages__instructions-wrapper">
{{> icon block="mail-messages__instructions-icon" icon="modal-success"}}
<div class="mail-messages__instructions-text">
<span class="mail-messages__instructions-text-selected">{{selectedMessages.length}} Messages selected</span>
<span>Click here to clear the selection</span>
</div>
</div>
<div class="rc-tags">
{{#each user in selectedUsers}}
{{> tag user}}
{{/each}}
<input type="text" class="rc-tags__input" placeholder="{{_ "Username_Placeholder"}}" name="users" autocomplete="off"/>
</div>
{{else}}
<div class="mail-messages__instructions">
<div class="mail-messages__instructions-wrapper">
{{> icon block="mail-messages__instructions-icon" icon="hand-pointer"}}
<div class="mail-messages__instructions-text">
Click the messages you would like to send by e-mail
</div>
</div>
</div>
{{#with config}}
{{#if autocomplete 'isShowing'}}
<div class="fadeInDown">
{{/if}}
<div class="rc-input rc-input--usernames">
<label class="rc-input__label">
<div class="rc-input__title">{{_ "To_users"}}</div>
<div class="rc-input__wrapper">
<div class="rc-input__icon">
{{> icon block="rc-input__icon-svg" icon="at"}}
</div>
<div class="rc-tags">
{{#each user in selectedUsers}}
{{> tag user}}
{{/each}}
<input type="text" class="rc-tags__input" placeholder="{{_ "Username_Placeholder"}}" name="users" autocomplete="off"/>
</div>
</div>
{{#with config}}
{{#if autocomplete 'isShowing'}}
{{#if autocomplete 'isLoaded'}}
{{> popupList data=config items=items}}
{{/if}}
</div>
{{/if}}
{{/with}}
</label>
</div>
<div class="rc-input rc-input--emails">
{{/if}}
{{/with}}
</label>
</div>
<div class="rc-input rc-input--emails">
<label class="rc-input__label">
<div class="rc-input__title">{{_ "To_additional_emails"}}</div>
<div class="rc-input__wrapper">
Expand All @@ -52,6 +70,14 @@
</div>
</label>
</div>

{{#if errorMessage}}
<div class="mail-messages__instructions mail-messages__instructions--warning">
<div class="mail-messages__instructions-wrapper">
<div class="mail-messages__instructions-text">{{errorMessage}}</div>
</div>
</div>
{{/if}}
</main>
<div class="rc-user-info__flex rc-user-info__row">
<button class="rc-button rc-button--outline js-cancel" title="{{_ 'Cancel'}}">{{_ 'Cancel'}}</button>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
/* global AutoComplete Deps */

import _ from 'underscore';
import toastr from 'toastr';
import resetSelection from '../resetSelection';

Expand Down Expand Up @@ -79,6 +77,9 @@ Template.mailMessagesInstructions.helpers({
selectedEmails() {
return Template.instance().selectedEmails.get();
},
selectedMessages() {
return Template.instance().selectedMessages.get();
},
config() {
const filter = Template.instance().userFilter;
return {
Expand All @@ -99,90 +100,62 @@ Template.mailMessagesInstructions.helpers({
},
items() {
return Template.instance().ac.filteredList();
},
errorMessage() {
return Template.instance().errorMessage.get();
}
});

Template.mailMessagesInstructions.events({
'click .js-cancel'(e, t) {
'click .js-cancel, click .mail-messages__instructions--selected'(e, t) {
t.reset(true);
},
'click .js-send'(e, t) {
t.$('.error').hide();
const $btn = t.$('button.send');
const oldBtnValue = $btn.html();
$btn.html(TAPi18n.__('Sending'));
const selectedMessages = $('.messages-box .message.selected');
let error = false;
if (selectedMessages.length === 0) {
t.$('.error-select').show();
error = true;
'click .js-send'(e, instance) {
const selectedUsers = instance.selectedUsers;
const selectedEmails = instance.selectedEmails;
const $emailsInput = instance.$('[name="emails"]');
const selectedMessages = instance.selectedMessages;
const subject = instance.$('[name="subject"]').val();

if (!selectedUsers.get().length && !selectedEmails.get().length && $emailsInput.val().trim() === '') {
instance.errorMessage.set(t('Mail_Message_Missing_to'));
return false;
}
if (t.$('input[name=to_emails]').val().trim()) {
const rfcMailPatternWithName = /^(?:.*<)?([a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)(?:>?)$/;
const emails = t.$('input[name=to_emails]').val().trim().split(',');
const erroredEmails = [];
emails.forEach((email) => {
if (!rfcMailPatternWithName.test(email.trim())) {
erroredEmails.push(email.trim());
}
});
t.erroredEmails.set(erroredEmails);
if (erroredEmails.length > 0) {
t.$('.error-invalid-emails').show();
error = true;

if ($emailsInput.val() !== '') {
if (isEmail($emailsInput.val())) {
const emailsArr = selectedEmails.get();
emailsArr.push({text: $emailsInput.val()});
$('[name="emails"]').val('');
selectedEmails.set(emailsArr);
} else {
instance.errorMessage.set(t('Mail_Message_Invalid_emails', $emailsInput.val()));
return false;
}
} else if (!t.selectedUsers.get().length) {
t.$('.error-missing-to').show();
error = true;
}
if (error) {
return $btn.html(oldBtnValue);

if (!selectedMessages.get().length) {
instance.errorMessage.set(t('Mail_Message_No_messages_selected_select_all'));
return false;
}

const data = {
rid: Session.get('openedRoom'),
to_users: t.selectedUsers.get(),
to_emails: t.$('input[name=to_emails]').val().trim(),
subject: t.$('input[name=subject]').val().trim(),
messages: selectedMessages.map(function(i, message) {
return message.id;
}).toArray(),
to_users: selectedUsers.get().map(user => user.username),
to_emails: selectedEmails.get().map(email => email.text).toString(),
subject,
messages: selectedMessages.get(),
language: localStorage.getItem('userLanguage')
};
return Meteor.call('mailMessages', data, function(err, result) {
$btn.html(oldBtnValue);

Meteor.call('mailMessages', data, function(err, result) {
if (err != null) {
return handleError(err);
}
console.log(result);
toastr.success(TAPi18n.__('Your_email_has_been_queued_for_sending'));
return t.reset();
});
},
'click .select-all'(e, t) {
t.$('.error-select').hide();
const view = Blaze.getView($('.messages-box')[0]);
if (view != null) {
if (typeof view.templateInstance === 'function') {
const chat = ChatMessage.find({
rid: Session.get('openedRoom')
});
view.templateInstance().selectedMessages = _.pluck(chat && chat.fetch(), '_id');
}
}
return $('.messages-box .message').addClass('selected');
},
'autocompleteselect #to_users'(event, instance, doc) {
instance.selectedUsers.set(instance.selectedUsers.get().concat(doc.username));
event.currentTarget.value = '';
return event.currentTarget.focus();
},
'click .remove-to-user'() {
let users = Template.instance().selectedUsers.get();
users = _.reject(Template.instance().selectedUsers.get(), (_id) => {
return _id === this.valueOf();
toastr.success(t('Your_email_has_been_queued_for_sending'));
instance.reset(true);
});
Template.instance().selectedUsers.set(users);
return $('#to_users').focus();
},
'click .rc-input--usernames .rc-tags__tag'({target}, t) {
const {username} = Blaze.getData(target);
Expand Down Expand Up @@ -263,11 +236,27 @@ Template.mailMessagesInstructions.onRendered(function() {
usersArr.push(item);
users.set(usersArr);
});

const selectedMessages = this.selectedMessages;

$('.messages-box .message').on('click', function() {
const id = this.id;
const messages = selectedMessages.get();

if ($(this).hasClass('selected')) {
selectedMessages.set(messages.filter(message => message !== id));
} else {
selectedMessages.set(messages.concat(id));
}
});
});

Template.mailMessagesInstructions.onCreated(function() {
resetSelection(true);

this.selectedEmails = new ReactiveVar([]);
this.selectedMessages = new ReactiveVar([]);
this.errorMessage = new ReactiveVar('');
this.selectedUsers = new ReactiveVar([]);
this.userFilter = new ReactiveVar('');

Expand Down Expand Up @@ -301,16 +290,13 @@ Template.mailMessagesInstructions.onCreated(function() {
]

});

this.ac.tmplInst = this;

this.selectedEmails = new ReactiveVar([]);

this.autoCompleteCollection = new Mongo.Collection(null);
this.erroredEmails = new ReactiveVar([]);
this.reset = (bool) => {
this.selectedUsers.set([]);
this.selectedEmails.set([]);
this.selectedMessages.set([]);
this.errorMessage.set('');
resetSelection(bool);
};
});
Expand Down
2 changes: 1 addition & 1 deletion packages/rocketchat-i18n/i18n/en.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -1154,7 +1154,7 @@
"mail-messages_description": "Permission to use the mail messages option",
"Mail_Message_Invalid_emails": "You have provided one or more invalid emails: %s",
"Mail_Message_Missing_to": "You must select one or more users or provide one or more email addresses, separated by commas.",
"Mail_Message_No_messages_selected_select_all": "You haven't selected any messages. Would you like to <a href='#' class='select-all'>select all</a> visible messages?",
"Mail_Message_No_messages_selected_select_all": "You haven't selected any messages",
"Mail_Messages": "Mail Messages",
"Mail_Messages_Instructions": "Choose which messages you want to send via email by clicking the messages",
"Mail_Messages_Subject": "Here's a selected portion of %s messages",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,3 +222,67 @@
color: #9ea2a8;
}
}

.contextual-bar__content.mail-messages {
& .rc-popup-list {
z-index: 1;
}

& .rc-input:not(:last-child) {
margin-bottom: 2rem;
}
}

.mail-messages__instructions {
display: flex;
border-width: 1px;
border-color: var(--rc-color-alert-message-primary);
background: var(--rc-color-alert-message-primary-background);
border-radius: 2px;
color: var(--rc-color-alert-message-primary);
padding: 1.25rem;
margin-bottom: 3rem;

&--selected {
background: var(--rc-color-alert-message-secondary-background);
border-color: var(--rc-color-alert-message-secondary);
color: var(--rc-color-alert-message-secondary);

cursor: pointer;
}

&--warning {
color: var(--rc-color-alert-message-warning);
border-color: var(--rc-color-alert-message-warning);
background: var(--rc-color-alert-message-warning-background);
}

&-wrapper {
display: flex;
margin: 0 -10px;
}

&-icon {
font-size: 2rem;
margin: 0 10px;

&--hand-pointer {
transform: rotate3d(0, 0, 1, -25deg);
margin: 0 15px;
fill: currentColor;
}
}

&-text {
font-size: 0.875rem;
font-weight: 600;
margin: 0 10px;
display: flex;
flex-direction: column;
line-height: 1.2rem;

&-selected {
font-weight: 400;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@
--rc-color-button-primary: #1d74f5;
--rc-color-button-primary-light: #175cc4;

--rc-color-alert-message-primary: var(--rc-color-button-primary);
--rc-color-alert-message-primary-background: #f1f6ff;
--rc-color-alert-message-secondary: #7ca52b;
--rc-color-alert-message-secondary-background: #fafff1;
--rc-color-alert-message-warning: #d52d24;
--rc-color-alert-message-warning-background: #fff3f3;

--rc-color-primary: var(--color-dark);
--rc-color-primary-darkest: var(--color-darkest);
--rc-color-primary-dark: var(--color-dark-medium);
Expand Down
1 change: 1 addition & 0 deletions packages/rocketchat-ui-master/public/icons.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 0 additions & 1 deletion tests/end-to-end/ui/12-settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,6 @@ describe('[Api Settings Change]', () => {
const userEl = admin.getUserFromList(`setting${ username }`);
userEl.waitForVisible(5000);
userEl.click();
flexTab.userViewTabButton.click();
flexTab.usersView.waitForVisible(5000);
});

Expand Down