Better error messages when topics can't load

This commit is contained in:
Robin Ward 2013-02-25 18:38:11 -05:00
parent d9d3419a51
commit 397c6ca761
5 changed files with 84 additions and 75 deletions

View File

@ -142,18 +142,15 @@ Discourse.Topic = Discourse.Model.extend({
}, },
toggleStar: function() { toggleStar: function() {
var _this = this; var topic = this;
this.toggleProperty('starred'); topic.toggleProperty('starred');
return jQuery.ajax({ return jQuery.ajax({
url: "" + (this.get('url')) + "/star", url: "" + (this.get('url')) + "/star",
type: 'PUT', type: 'PUT',
data: { data: { starred: topic.get('starred') ? true : false },
starred: this.get('starred') ? true : false
},
error: function(error) { error: function(error) {
var errors; topic.toggleProperty('starred');
_this.toggleProperty('starred'); var errors = jQuery.parseJSON(error.responseText).errors;
errors = jQuery.parseJSON(error.responseText).errors;
return bootbox.alert(errors[0]); return bootbox.alert(errors[0]);
} }
}); });
@ -203,31 +200,22 @@ Discourse.Topic = Discourse.Model.extend({
// Load the posts for this topic // Load the posts for this topic
loadPosts: function(opts) { loadPosts: function(opts) {
var _this = this; var topic = this;
if (!opts) {
opts = {}; if (!opts) opts = {};
}
// Load the first post by default // Load the first post by default
if (!opts.bestOf) { if ((!opts.bestOf) && (!opts.nearPost)) opts.nearPost = 1;
if (!opts.nearPost) opts.nearPost = 1
}
// If we already have that post in the DOM, jump to it // If we already have that post in the DOM, jump to it
if (Discourse.TopicView.scrollTo(this.get('id'), opts.nearPost)) return; if (Discourse.TopicView.scrollTo(this.get('id'), opts.nearPost)) return;
return Discourse.Topic.find(this.get('id'), { // If loading the topic succeeded...
nearPost: opts.nearPost, var afterTopicLoaded = function(result) {
bestOf: opts.bestOf,
trackVisit: opts.trackVisit
}).then(function(result) {
// If loading the topic succeeded...
// Update the slug if different
var closestPostNumber, lastPost, postDiff; var closestPostNumber, lastPost, postDiff;
if (result.slug) {
_this.set('slug', result.slug); // Update the slug if different
} if (result.slug) topic.set('slug', result.slug);
// If we want to scroll to a post that doesn't exist, just pop them to the closest // If we want to scroll to a post that doesn't exist, just pop them to the closest
// one instead. This is likely happening due to a deleted post. // one instead. This is likely happening due to a deleted post.
@ -235,34 +223,29 @@ Discourse.Topic = Discourse.Model.extend({
closestPostNumber = 0; closestPostNumber = 0;
postDiff = Number.MAX_VALUE; postDiff = Number.MAX_VALUE;
result.posts.each(function(p) { result.posts.each(function(p) {
var diff; var diff = Math.abs(p.post_number - opts.nearPost);
diff = Math.abs(p.post_number - opts.nearPost);
if (diff < postDiff) { if (diff < postDiff) {
postDiff = diff; postDiff = diff;
closestPostNumber = p.post_number; closestPostNumber = p.post_number;
if (diff === 0) { if (diff === 0) return false;
return false;
}
} }
}); });
opts.nearPost = closestPostNumber; opts.nearPost = closestPostNumber;
if (_this.get('participants')) { if (topic.get('participants')) {
_this.get('participants').clear(); topic.get('participants').clear();
} }
if (result.suggested_topics) { if (result.suggested_topics) {
_this.set('suggested_topics', Em.A()); topic.set('suggested_topics', Em.A());
} }
_this.mergeAttributes(result, { topic.mergeAttributes(result, { suggested_topics: Discourse.Topic });
suggested_topics: Discourse.Topic topic.set('posts', Em.A());
});
_this.set('posts', Em.A());
if (opts.trackVisit && result.draft && result.draft.length > 0) { if (opts.trackVisit && result.draft && result.draft.length > 0) {
Discourse.openComposer({ Discourse.openComposer({
draft: Discourse.Draft.getLocal(result.draft_key, result.draft), draft: Discourse.Draft.getLocal(result.draft_key, result.draft),
draftKey: result.draft_key, draftKey: result.draft_key,
draftSequence: result.draft_sequence, draftSequence: result.draft_sequence,
topic: _this, topic: topic,
ignoreIfChanged: true ignoreIfChanged: true
}); });
} }
@ -273,15 +256,41 @@ Discourse.Topic = Discourse.Model.extend({
var post; var post;
p.scrollToAfterInsert = opts.nearPost; p.scrollToAfterInsert = opts.nearPost;
post = Discourse.Post.create(p); post = Discourse.Post.create(p);
post.set('topic', _this); post.set('topic', topic);
_this.get('posts').pushObject(post); topic.get('posts').pushObject(post);
lastPost = post; lastPost = post;
}); });
return _this.set('loaded', true); topic.set('loaded', true);
}, function(result) { }
_this.set('missing', true);
return _this.set('message', Em.String.i18n('topic.not_found.description')); var errorLoadingTopic = function(result) {
}); topic.set('errorLoading', true);
// If the result was 404 the post is not found
if (result.status == 404) {
topic.set('errorTitle', Em.String.i18n('topic.not_found.title'))
topic.set('message', Em.String.i18n('topic.not_found.description'));
return;
}
// If the result is 403 it means invalid access
if (result.status == 403) {
topic.set('errorTitle', Em.String.i18n('topic.invalid_access.title'))
topic.set('message', Em.String.i18n('topic.invalid_access.description'));
return;
}
// Otherwise supply a generic error message
topic.set('errorTitle', Em.String.i18n('topic.server_error.title'))
topic.set('message', Em.String.i18n('topic.server_error.description'));
}
// Finally, call our find method
Discourse.Topic.find(this.get('id'), {
nearPost: opts.nearPost,
bestOf: opts.bestOf,
trackVisit: opts.trackVisit
}).then(afterTopicLoaded, errorLoadingTopic);
}, },
notificationReasonText: (function() { notificationReasonText: (function() {
@ -324,10 +333,10 @@ Discourse.Topic = Discourse.Model.extend({
isReplyDirectlyBelow: function(post) { isReplyDirectlyBelow: function(post) {
var postBelow, posts; var postBelow, posts;
posts = this.get('posts'); posts = this.get('posts');
if (!posts) { if (!posts) return;
return;
}
postBelow = posts[posts.indexOf(post) + 1]; postBelow = posts[posts.indexOf(post) + 1];
// If the post directly below's reply_to_post_number is our post number, it's // If the post directly below's reply_to_post_number is our post number, it's
// considered directly below. // considered directly below.
return (postBelow ? postBelow.get('reply_to_post_number') : void 0) === post.get('post_number'); return (postBelow ? postBelow.get('reply_to_post_number') : void 0) === post.get('post_number');
@ -346,12 +355,13 @@ window.Discourse.Topic.reopenClass({
// options: // options:
// onLoad - the callback after the topic is loaded // onLoad - the callback after the topic is loaded
find: function(topicId, opts) { find: function(topicId, opts) {
var data, promise, url, var data, promise, url;
_this = this;
url = "/t/" + topicId; url = "/t/" + topicId;
if (opts.nearPost) { if (opts.nearPost) {
url += "/" + opts.nearPost; url += "/" + opts.nearPost;
} }
data = {}; data = {};
if (opts.postsAfter) { if (opts.postsAfter) {
data.posts_after = opts.postsAfter; data.posts_after = opts.postsAfter;
@ -397,15 +407,11 @@ window.Discourse.Topic.reopenClass({
movePosts: function(topicId, title, postIds) { movePosts: function(topicId, title, postIds) {
return jQuery.ajax("/t/" + topicId + "/move-posts", { return jQuery.ajax("/t/" + topicId + "/move-posts", {
type: 'POST', type: 'POST',
data: { data: { title: title, post_ids: postIds }
title: title,
post_ids: postIds
}
}); });
}, },
create: function(obj, topicView) { create: function(obj, topicView) {
var _this = this;
return Object.tap(this._super(obj), function(result) { return Object.tap(this._super(obj), function(result) {
if (result.participants) { if (result.participants) {
result.participants = result.participants.map(function(u) { result.participants = result.participants.map(function(u) {
@ -413,9 +419,7 @@ window.Discourse.Topic.reopenClass({
}); });
result.fewParticipants = Em.A(); result.fewParticipants = Em.A();
return result.participants.each(function(p) { return result.participants.each(function(p) {
if (result.fewParticipants.length >= 8) { if (result.fewParticipants.length >= 8) return false;
return false;
}
result.fewParticipants.pushObject(p); result.fewParticipants.pushObject(p);
return true; return true;
}); });

View File

@ -8,7 +8,7 @@
{{#if view.showFavoriteButton}} {{#if view.showFavoriteButton}}
<a {{bindAttr class=":star view.topic.starred:starred"}} {{action toggleStar target="controller"}} href='#' title="{{i18n favorite.help}}"></a> <a {{bindAttr class=":star view.topic.starred:starred"}} {{action toggleStar target="controller"}} href='#' title="{{i18n favorite.help}}"></a>
{{/if}} {{/if}}
{{#if view.editingTopic}} {{#if view.editingTopic}}
<input id='edit-title' type='text' {{bindAttr value="view.topic.title"}}> <input id='edit-title' type='text' {{bindAttr value="view.topic.title"}}>
{{view Discourse.ComboboxViewCategory valueAttribute="name" contentBinding="view.categories" valueBinding="view.topic.categoryName"}} {{view Discourse.ComboboxViewCategory valueAttribute="name" contentBinding="view.categories" valueBinding="view.topic.categoryName"}}
<button class='btn btn-primary btn-small' {{action finishedEdit target="view"}}><i class='icon-ok'></i></button> <button class='btn btn-primary btn-small' {{action finishedEdit target="view"}}><i class='icon-ok'></i></button>
@ -19,8 +19,8 @@
{{view Discourse.TopicStatusView topicBinding="view.topic"}} {{view Discourse.TopicStatusView topicBinding="view.topic"}}
<a href='{{unbound view.topic.url}}'>{{{unbound view.topic.fancy_title}}}</a> <a href='{{unbound view.topic.url}}'>{{{unbound view.topic.fancy_title}}}</a>
{{else}} {{else}}
{{#if view.topic.missing}} {{#if view.topic.errorLoading}}
{{i18n topic.not_found.title}} {{view.topic.errorTitle}}
{{else}} {{else}}
{{i18n topic.loading}} {{i18n topic.loading}}
{{/if}} {{/if}}
@ -33,7 +33,7 @@
</h1> </h1>
{{/if}} {{/if}}
</div> </div>
</div> </div>
</div> </div>
{{/if}} {{/if}}
@ -102,7 +102,7 @@
{{/if}} {{/if}}
</section> </section>
</div> </div>
</div> </div>

View File

@ -7,8 +7,8 @@
{{view Discourse.TopicStatusView topicBinding="view.topic"}} {{view Discourse.TopicStatusView topicBinding="view.topic"}}
<a class='topic-link' href='{{unbound view.topic.url}}'>{{{view.topic.fancy_title}}}</a> <a class='topic-link' href='{{unbound view.topic.url}}'>{{{view.topic.fancy_title}}}</a>
{{else}} {{else}}
{{#if view.topic.missing}} {{#if view.topic.errorLoading}}
{{i18n topic.not_found.title}} {{topic.errorTitle}}
{{else}} {{else}}
{{i18n topic.loading}} {{i18n topic.loading}}
{{/if}} {{/if}}

View File

@ -129,12 +129,12 @@ class TopicsController < ApplicationController
end end
def timings def timings
PostTiming.process_timings( PostTiming.process_timings(
current_user, current_user,
params[:topic_id].to_i, params[:topic_id].to_i,
params[:highest_seen].to_i, params[:highest_seen].to_i,
params[:topic_time].to_i, params[:topic_time].to_i,
(params[:timings] || []).map{|post_number, t| [post_number.to_i, t.to_i]} (params[:timings] || []).map{|post_number, t| [post_number.to_i, t.to_i]}
) )

View File

@ -170,7 +170,7 @@ en:
filters: filters:
all: "All" all: "All"
stream: stream:
posted_by: "Posted by" posted_by: "Posted by"
sent_by: "Sent by" sent_by: "Sent by"
@ -341,10 +341,15 @@ en:
title: 'Topic' title: 'Topic'
loading_more: "Loading more Topics..." loading_more: "Loading more Topics..."
loading: 'Loading topic...' loading: 'Loading topic...'
missing: "Topic Not Found" invalid_access:
title: "You can't do that!"
description: "You don't have access to view that topic."
server_error:
title: "Error loading topic!"
description: "Sorry, we couldn't load that topic, possibly due to a connection problem. Please try again."
not_found: not_found:
title: "Topic Not Found" title: "Topic not found!"
description: "Sorry, we couldn't load that topic, possibly due to a connection problem. Please try again. If the problem persists, perhaps the topic was deleted." description: "That topic could not be found. It's likely it was deleted by a moderator."
unread_posts: "you have {{unread}} unread old posts in this topic" unread_posts: "you have {{unread}} unread old posts in this topic"
new_posts: "there are {{new_posts}} new posts in this topic since you last read it" new_posts: "there are {{new_posts}} new posts in this topic since you last read it"
likes: "there are {{likes}} likes in this topic" likes: "there are {{likes}} likes in this topic"