Skip to content

Commit

Permalink
Release Messaging center (mozilla#3420)
Browse files Browse the repository at this point in the history
This is the final step of functional changes to the Messaging center before we can start using it in production:

* Messaging link is added to the main menu, visible only to users that can actually access the page
* As soon as you hit the Review page, contributors start getting fetched, as indicated in the button in the bottom right part of the screen.
* Once fetching is complete, the button to send the messages is made available with the recipient count written over it.
* While messages are being sent or if the recipient count is 0, the Send button is disabled.
* If fetching contributors fails, the button turns red and offers you the ability to retry fetching.

Other changes:
* Change styling of the No messages sent yet. page
* Only filter users by Min and Max values if they are actually set
* Only filter by actions if set
* Prefetch user profile data if sending as email 
* Fix margin in the Recipients section of the Review
  • Loading branch information
mathjazz authored Nov 16, 2024
1 parent ff529a9 commit b8fb1d0
Show file tree
Hide file tree
Showing 7 changed files with 210 additions and 55 deletions.
3 changes: 3 additions & 0 deletions pontoon/base/templates/header.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
<li><a href="{{ url('pontoon.teams') }}">Teams</a></li>
<li><a href="{{ url('pontoon.projects') }}">Projects</a></li>
<li><a href="{{ url('pontoon.contributors') }}">Contributors</a></li>
{% if user.is_authenticated and user.is_superuser %}
<li><a href="{{ url('pontoon.messaging.compose') }}">Messaging</a></li>
{% endif %}
<li><a href="{{ url('pontoon.machinery') }}">Machinery</a></li>
</ul>

Expand Down
7 changes: 7 additions & 0 deletions pontoon/messaging/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ class MessageForm(forms.ModelForm):
body = HtmlField()
send_to_myself = forms.BooleanField(required=False)

recipient_ids = forms.CharField(
required=False,
widget=forms.Textarea(),
validators=[validators.validate_comma_separated_integer_list],
)

locales = forms.CharField(
widget=forms.Textarea(),
validators=[validators.validate_comma_separated_integer_list],
Expand All @@ -19,6 +25,7 @@ class MessageForm(forms.ModelForm):
class Meta:
model = Message
fields = [
"recipient_ids",
"notification",
"email",
"transactional",
Expand Down
46 changes: 40 additions & 6 deletions pontoon/messaging/static/css/messaging.css
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,45 @@
.fa-chevron-right {
margin-left: 5px;
}
.fa-spin {
font-size: 16px;
}
}

.button:hover {
color: inherit;
}

.button.fetching {
pointer-events: none;
}

.button.fetch-again {
display: none;
background-color: var(--status-error);
color: var(--translation-main-button-color);
}

.button.active {
display: none;
width: auto;

.fa-spin {
display: none;
}
}

.button.disabled {
pointer-events: none;
}

.button.active.sending {
pointer-events: none;
.fa-spin {
display: inline;
}
}

.right {
float: right;

Expand Down Expand Up @@ -126,6 +159,7 @@
}

input#id_send_to_myself,
textarea#id_recipient_ids,
textarea#id_body {
display: none;
}
Expand Down Expand Up @@ -181,8 +215,8 @@
}

.recipients {
> div:not(:last-child) {
margin-bottom: 20px;
> div {
margin-top: 20px;
}

h5 {
Expand Down Expand Up @@ -210,14 +244,14 @@
text-align: center;

.icon {
color: var(--light-grey-1);
color: var(--background-hover-2);
font-size: 100px;
}

.title {
color: var(--light-grey-6);
font-size: 20px;
font-weight: 100;
color: var(--light-grey-7);
font-size: 18px;
font-weight: bold;
}
}

Expand Down
74 changes: 67 additions & 7 deletions pontoon/messaging/static/js/messaging.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ $(function () {
const converter = new showdown.Converter({
simpleLineBreaks: true,
});
const nf = new Intl.NumberFormat('en');
let inProgress = false;

function validateForm() {
Expand Down Expand Up @@ -73,6 +74,38 @@ $(function () {
);
}

function fetchRecipients() {
$('#review .controls .fetching').show();
$('#review .controls .fetch-again').hide();
$('#review .controls .send.active')
.hide()
.removeClass('disabled')
.find('.value')
.html('');

$.ajax({
url: '/messaging/ajax/fetch-recipients/',
type: 'POST',
data: $('#send-message').serialize(),
success: function (data) {
const count = nf.format(data.recipients.length);
$('#review .controls .send.active')
.show()
.toggleClass('disabled', !data.recipients.length)
.find('.value')
.html(count);
$('#compose [name=recipient_ids]').val(data.recipients);
},
error: function () {
Pontoon.endLoader('Fetching recipients failed.', 'error');
$('#review .controls .fetch-again').show();
},
complete: function () {
$('#review .controls .fetching').hide();
},
});
}

function updateReviewPanel() {
function updateMultipleItemSelector(source, target, item) {
const allProjects = !$(`${source}.available li:not(.no-match)`).length;
Expand All @@ -98,7 +131,12 @@ $(function () {
let value = $(this).find('input').val().trim();
if (value) {
if (className === 'date') {
value = new Date(value).toLocaleDateString();
// Convert date to the format used in the input field
// and set timezone to UTC to prevent shifts by a day
// when using the local timezone.
value = new Date(value).toLocaleDateString(undefined, {
timeZone: 'UTC',
});
}
values.push(`${label}: ${value}`);
show = true;
Expand All @@ -110,17 +148,19 @@ $(function () {
$(`#review .${filter}`).toggle(show);
}

// Update hidden textarea with the HTML content to be sent to backend
const bodyValue = $('#body').val();
const html = converter.makeHtml(bodyValue);
$('#compose [name=body]').val(html);

fetchRecipients();

// Subject
$('#review .subject .value').html($('#id_subject').val());

// Body
const bodyValue = $('#body').val();
const html = converter.makeHtml(bodyValue);
$('#review .body .value').html(html);

// Update hidden textarea with the HTML content to be sent to backend
$('#compose [name=body]').val(html);

// User roles
const userRoles = $('#compose .user-roles .enabled')
.map(function () {
Expand Down Expand Up @@ -291,12 +331,25 @@ $(function () {
window.scrollTo(0, 0);
});

// Fetch recipients again
container.on('click', '.controls .fetch-again', function (e) {
e.preventDefault();
fetchRecipients();
});

// Send message
container.on('click', '.controls .send.button', function (e) {
e.preventDefault();

const $form = $('#send-message');
const sendToMyself = $(this).is('.to-myself');
const button = $(this);

if (button.is('.sending')) {
return;
}

button.addClass('sending');

// Distinguish between Send and Send to myself
$('#id_send_to_myself').prop('checked', sendToMyself);
Expand All @@ -309,12 +362,19 @@ $(function () {
success: function () {
Pontoon.endLoader('Message sent.');
if (!sendToMyself) {
container.find('.left-column .sent a').click();
const count = container.find('.left-column .sent .count');
// Update count in the menu
count.html(parseInt(count.html(), 10) + 1);
// Load Sent panel
count.parents('a').click();
}
},
error: function () {
Pontoon.endLoader('Oops, something went wrong.', 'error');
},
complete: function () {
button.removeClass('sending');
},
});
});
});
7 changes: 5 additions & 2 deletions pontoon/messaging/templates/messaging/includes/compose.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<form id="send-message" method="POST" action="{{ url('pontoon.messaging.ajax.send_message') }}">
{% csrf_token %}
{{ form.send_to_myself }}
{{ form.recipient_ids }}

<section class="message-type">
<h3>Message type</h3>
Expand Down Expand Up @@ -217,8 +218,10 @@ <h3>Message type</h3>
<button class="button toggle edit" data-target="#compose"><span class="fa fa-chevron-left"></span>Back to
editing</button>
<div class="right">
<button class="button send to-myself">Send test to myself</button>
<button class="button active send">Send</button>
<button class="button send to-myself">Send to myself</button>
<button class="button fetching">Fetching recipients… <i class="fa fa-circle-notch fa-spin"></i></button>
<button class="button fetch-again">Fetch recipients again?</button>
<button class="button active send">Send to <span class="value"></span> recipients <i class="fa fa-circle-notch fa-spin"></i></button>
</div>
</menu>
</div>
6 changes: 6 additions & 0 deletions pontoon/messaging/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@
views.ajax_sent,
name="pontoon.messaging.ajax.sent",
),
# Fetch recipients
path(
"fetch-recipients/",
views.fetch_recipients,
name="pontoon.messaging.ajax.fetch_recipients",
),
# Send message
path(
"send/",
Expand Down
Loading

0 comments on commit b8fb1d0

Please sign in to comment.