Allow re-send of messages in msg detail view on OutgoingKeyError

We also show more errors than we used to in the MessageDetail screen
to help make it clear what is happening, and why the user would need to
re-send.

FREEBIE
pull/749/head
Scott Nonnenberg 8 years ago
parent 47c5142a83
commit a827334c3e

@ -61,6 +61,10 @@
} }
} }
}, },
"retryDescription": {
"message": "You can retry sending this message to each of the failed recipients with these buttons:",
"description": "Shows on the message details view when it's a message error which can be retried."
},
"sendAnyway": { "sendAnyway": {
"message": "Send Anyway", "message": "Send Anyway",
"description": "Used on a warning dialog to specifiy " "description": "Used on a warning dialog to specifiy "

@ -293,6 +293,14 @@
<script type='text/x-tmpl-mustache' id='message-detail'> <script type='text/x-tmpl-mustache' id='message-detail'>
<div class='container'> <div class='container'>
<div class='message-container'></div> <div class='message-container'></div>
{{ #allowRetry }}
<div class='retries'>
<div>{{ retryDescription }}</div>
{{ #retryTargets }}
<button class='retry gray' data-number='{{ number }}'>{{ title }}</button>
{{ /retryTargets }}
</div>
{{ /allowRetry }}
<div class='info'> <div class='info'>
<table> <table>
{{ #errors }} {{ #errors }}

@ -199,6 +199,15 @@
} }
this.save({sent: true, expirationStartTimestamp: now}); this.save({sent: true, expirationStartTimestamp: now});
this.sendSyncMessage(); this.sendSyncMessage();
// var error = new Error('OutgoingIdentityKeyError');
// error.name = 'OutgoingIdentityKeyError';
// error.number = result.successfulNumbers[0];
// throw error;
// var error = new Error('OutgoingMessageError');
// error.name = 'OutgoingMessageError';
// throw error;
}.bind(this)).catch(function(result) { }.bind(this)).catch(function(result) {
var now = Date.now(); var now = Date.now();
this.trigger('done'); this.trigger('done');
@ -273,7 +282,8 @@
(e.name === 'MessageError' || (e.name === 'MessageError' ||
e.name === 'OutgoingMessageError' || e.name === 'OutgoingMessageError' ||
e.name === 'SendMessageNetworkError' || e.name === 'SendMessageNetworkError' ||
e.name === 'SignedPreKeyRotationError'); e.name === 'SignedPreKeyRotationError' ||
e.name === 'OutgoingIdentityKeyError');
}); });
this.set({errors: errors[1]}); this.set({errors: errors[1]});
return errors[0][0]; return errors[0][0];
@ -282,9 +292,9 @@
return (e.name === 'MessageError' || return (e.name === 'MessageError' ||
e.name === 'OutgoingMessageError' || e.name === 'OutgoingMessageError' ||
e.name === 'SendMessageNetworkError' || e.name === 'SendMessageNetworkError' ||
e.name === 'SignedPreKeyRotationError'); e.name === 'SignedPreKeyRotationError' ||
e.name === 'OutgoingIdentityKeyError');
}, },
resend: function(number) { resend: function(number) {
var error = this.removeOutgoingErrors(number); var error = this.removeOutgoingErrors(number);
if (error) { if (error) {
@ -292,7 +302,6 @@
this.send(promise); this.send(promise);
} }
}, },
handleDataMessage: function(dataMessage) { handleDataMessage: function(dataMessage) {
// This function can be called from the background script on an // This function can be called from the background script on an
// incoming message or from the frontend after the user accepts an // incoming message or from the frontend after the user accepts an

@ -10,8 +10,7 @@
templateName: 'contact-detail', templateName: 'contact-detail',
initialize: function(options) { initialize: function(options) {
this.errors = _.reject(options.errors, function(e) { this.errors = _.reject(options.errors, function(e) {
return (e.name === 'IncomingIdentityKeyError' || return (e.name === 'OutgoingIdentityKeyError' ||
e.name === 'OutgoingIdentityKeyError' ||
e.name === 'OutgoingMessageError' || e.name === 'OutgoingMessageError' ||
e.name === 'SendMessageNetworkError'); e.name === 'SendMessageNetworkError');
}); });
@ -36,6 +35,33 @@
this.listenTo(this.model, 'change', this.render); this.listenTo(this.model, 'change', this.render);
}, },
events: {
'click button.retry': 'onRetry'
},
onRetry: function(e) {
var number = _.find(e.target.attributes, function(attribute) {
return attribute.name === 'data-number';
});
if (number) {
this.model.resend(number.value);
}
},
getContact: function(number) {
var c = ConversationController.get(number);
return {
number: number,
title: c ? c.getTitle() : number
};
},
buildRetryTargetList: function() {
var targets = _.filter(this.model.get('errors'), function(e) {
return e.number && e.name === 'OutgoingIdentityKeyError';
});
return _.map(targets, function(e) {
return this.getContact(e.number);
}.bind(this));
},
contacts: function() { contacts: function() {
if (this.model.isIncoming()) { if (this.model.isIncoming()) {
var number = this.model.get('source'); var number = this.model.get('source');
@ -45,35 +71,36 @@
} }
}, },
renderContact: function(contact) { renderContact: function(contact) {
var grouped = _.groupBy(this.model.get('errors'), 'number');
var view = new ContactView({ var view = new ContactView({
model: contact, model: contact,
errors: this.errors[contact.id] errors: grouped[contact.id]
}).render(); }).render();
this.$('.contacts').append(view.el); this.$('.contacts').append(view.el);
}, },
render: function() { render: function() {
this.errors = _.groupBy(this.model.get('errors'), 'number'); var retryTargets = this.buildRetryTargetList();
var unknownErrors = this.errors['undefined']; var allowRetry = retryTargets.length > 0;
if (unknownErrors) {
unknownErrors = unknownErrors.filter(function(e) {
return (e.name !== 'MessageError');
});
}
this.$el.html(Mustache.render(_.result(this, 'template', ''), { this.$el.html(Mustache.render(_.result(this, 'template', ''), {
sent_at : moment(this.model.get('sent_at')).format('LLLL'), sent_at : moment(this.model.get('sent_at')).format('LLLL'),
received_at : this.model.isIncoming() ? moment(this.model.get('received_at')).format('LLLL') : null, received_at : this.model.isIncoming() ? moment(this.model.get('received_at')).format('LLLL') : null,
tofrom : this.model.isIncoming() ? i18n('from') : i18n('to'), tofrom : this.model.isIncoming() ? i18n('from') : i18n('to'),
errors : unknownErrors, errors : this.model.get('errors'),
allowRetry : allowRetry,
retryTargets : retryTargets,
title : i18n('messageDetail'), title : i18n('messageDetail'),
sent : i18n('sent'), sent : i18n('sent'),
received : i18n('received'), received : i18n('received'),
errorLabel : i18n('error') errorLabel : i18n('error'),
retryDescription: i18n('retryDescription')
})); }));
this.view.$el.prependTo(this.$('.message-container')); this.view.$el.prependTo(this.$('.message-container'));
if (this.model.isOutgoing()) { if (this.model.isOutgoing()) {
this.conversation.contactCollection.reject(function(c) { this.conversation.contactCollection.reject(function(c) {
return c.id === textsecure.storage.user.getNumber(); return c.isMe();
}).forEach(this.renderContact.bind(this)); }).forEach(this.renderContact.bind(this));
} else { } else {
this.renderContact( this.renderContact(

@ -159,6 +159,13 @@
} }
} }
.retries {
padding: 1em;
}
button.retry {
margin: 0.5em;
}
.contacts .contact-detail { .contacts .contact-detail {
padding: 0 36px; padding: 0 36px;
margin-bottom: 5px; margin-bottom: 5px;

@ -1125,6 +1125,10 @@ input.search {
font-weight: bold; } font-weight: bold; }
.message-detail .info button span { .message-detail .info button span {
vertical-align: middle; } vertical-align: middle; }
.message-detail .retries {
padding: 1em; }
.message-detail button.retry {
margin: 0.5em; }
.message-detail .contacts .contact-detail { .message-detail .contacts .contact-detail {
padding: 0 36px; padding: 0 36px;
margin-bottom: 5px; } margin-bottom: 5px; }

Loading…
Cancel
Save